Commit bee943baab1ac3ec038553019240fa1e26f88047
1 parent
9495c29d
Initial implementation of Asset, Relation and Alarm services
Showing
66 changed files
with
3803 additions
and
161 deletions
Too many changes to show.
To preserve performance only 66 of 185 files are displayed.
... | ... | @@ -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); |
... | ... | @@ -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); |
... | ... | @@ -387,6 +449,16 @@ public abstract class BaseController { |
387 | 449 | return plugin; |
388 | 450 | } |
389 | 451 | |
452 | + protected PluginMetaData checkPlugin(PluginId pluginId) throws ThingsboardException { | |
453 | + checkNotNull(pluginId); | |
454 | + return checkPlugin(pluginService.findPluginById(pluginId)); | |
455 | + } | |
456 | + | |
457 | + protected RuleMetaData checkRule(RuleId ruleId) throws ThingsboardException { | |
458 | + checkNotNull(ruleId); | |
459 | + return checkRule(ruleService.findRuleById(ruleId)); | |
460 | + } | |
461 | + | |
390 | 462 | protected RuleMetaData checkRule(RuleMetaData rule) throws ThingsboardException { |
391 | 463 | checkNotNull(rule); |
392 | 464 | SecurityUser authUser = getCurrentUser(); |
... | ... | @@ -412,7 +484,8 @@ public abstract class BaseController { |
412 | 484 | if (request.getHeader("x-forwarded-port") != null) { |
413 | 485 | try { |
414 | 486 | serverPort = request.getIntHeader("x-forwarded-port"); |
415 | - } catch (NumberFormatException e) {} | |
487 | + } catch (NumberFormatException e) { | |
488 | + } | |
416 | 489 | } |
417 | 490 | |
418 | 491 | String baseUrl = String.format("%s://%s:%d", | ... | ... |
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 | } | ... | ... |
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.AssetId; | |
22 | +import org.thingsboard.server.common.data.id.EntityId; | |
23 | +import org.thingsboard.server.common.data.id.TenantId; | |
24 | + | |
25 | +/** | |
26 | + * Created by ashvayka on 11.05.17. | |
27 | + */ | |
28 | +@Data | |
29 | +public class Alarm extends BaseData<AlarmId> { | |
30 | + | |
31 | + private TenantId tenantId; | |
32 | + private String type; | |
33 | + private EntityId originator; | |
34 | + private AlarmSeverity severity; | |
35 | + private AlarmStatus status; | |
36 | + private long startTs; | |
37 | + private long endTs; | |
38 | + private long ackTs; | |
39 | + private long clearTs; | |
40 | + private JsonNode details; | |
41 | + private boolean propagate; | |
42 | + | |
43 | + public Alarm() { | |
44 | + super(); | |
45 | + } | |
46 | + | |
47 | + public Alarm(AlarmId id) { | |
48 | + super(id); | |
49 | + } | |
50 | + | |
51 | +} | ... | ... |
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.id.TenantId; | |
21 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
22 | + | |
23 | +/** | |
24 | + * Created by ashvayka on 11.05.17. | |
25 | + */ | |
26 | +@Data | |
27 | +public class AlarmQuery { | |
28 | + | |
29 | + private TenantId tenantId; | |
30 | + private EntityId affectedEntityId; | |
31 | + private TimePageLink pageLink; | |
32 | + private AlarmStatus status; | |
33 | + | |
34 | +} | ... | ... |
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 | + public boolean isAck() { | |
26 | + return this == ACTIVE_ACK || this == CLEARED_ACK; | |
27 | + } | |
28 | + | |
29 | + public boolean isCleared() { | |
30 | + return this == CLEARED_ACK || this == CLEARED_UNACK; | |
31 | + } | |
32 | + | |
33 | +} | ... | ... |
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 | +} | ... | ... |
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.id.EntityId; | |
21 | +import org.thingsboard.server.common.data.id.TenantId; | |
22 | +import org.thingsboard.server.dao.Dao; | |
23 | +import org.thingsboard.server.dao.model.AlarmEntity; | |
24 | + | |
25 | +/** | |
26 | + * Created by ashvayka on 11.05.17. | |
27 | + */ | |
28 | +public interface AlarmDao extends Dao<AlarmEntity> { | |
29 | + | |
30 | + ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type); | |
31 | + | |
32 | + AlarmEntity save(Alarm alarm); | |
33 | + | |
34 | +} | ... | ... |
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 lombok.extern.slf4j.Slf4j; | |
20 | +import org.springframework.stereotype.Component; | |
21 | +import org.thingsboard.server.common.data.alarm.Alarm; | |
22 | +import org.thingsboard.server.common.data.id.EntityId; | |
23 | +import org.thingsboard.server.common.data.id.TenantId; | |
24 | +import org.thingsboard.server.dao.AbstractModelDao; | |
25 | +import org.thingsboard.server.dao.model.AlarmEntity; | |
26 | + | |
27 | +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COLUMN_FAMILY_NAME; | |
28 | + | |
29 | +@Component | |
30 | +@Slf4j | |
31 | +public class AlarmDaoImpl extends AbstractModelDao<AlarmEntity> implements AlarmDao { | |
32 | + | |
33 | + @Override | |
34 | + protected Class<AlarmEntity> getColumnFamilyClass() { | |
35 | + return AlarmEntity.class; | |
36 | + } | |
37 | + | |
38 | + @Override | |
39 | + protected String getColumnFamilyName() { | |
40 | + return ALARM_COLUMN_FAMILY_NAME; | |
41 | + } | |
42 | + | |
43 | + @Override | |
44 | + public AlarmEntity save(Alarm alarm) { | |
45 | + log.debug("Save asset [{}] ", alarm); | |
46 | + return save(new AlarmEntity(alarm)); | |
47 | + } | |
48 | + | |
49 | + @Override | |
50 | + public ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type) { | |
51 | + return null; | |
52 | + } | |
53 | +} | ... | ... |
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.id.EntityId; | |
23 | +import org.thingsboard.server.common.data.page.TimePageData; | |
24 | + | |
25 | +import java.util.Optional; | |
26 | + | |
27 | +/** | |
28 | + * Created by ashvayka on 11.05.17. | |
29 | + */ | |
30 | +public interface AlarmService { | |
31 | + | |
32 | + Alarm createOrUpdateAlarm(Alarm alarm); | |
33 | + | |
34 | + ListenableFuture<Boolean> updateAlarm(Alarm alarm); | |
35 | + | |
36 | + ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTs); | |
37 | + | |
38 | + ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long ackTs); | |
39 | + | |
40 | + ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query); | |
41 | + | |
42 | +} | ... | ... |
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 | +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.alarm.Alarm; | |
29 | +import org.thingsboard.server.common.data.alarm.AlarmId; | |
30 | +import org.thingsboard.server.common.data.alarm.AlarmQuery; | |
31 | +import org.thingsboard.server.common.data.alarm.AlarmStatus; | |
32 | +import org.thingsboard.server.common.data.asset.Asset; | |
33 | +import org.thingsboard.server.common.data.id.AssetId; | |
34 | +import org.thingsboard.server.common.data.id.CustomerId; | |
35 | +import org.thingsboard.server.common.data.id.EntityId; | |
36 | +import org.thingsboard.server.common.data.id.TenantId; | |
37 | +import org.thingsboard.server.common.data.page.TextPageData; | |
38 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
39 | +import org.thingsboard.server.common.data.page.TimePageData; | |
40 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
41 | +import org.thingsboard.server.dao.asset.AssetDao; | |
42 | +import org.thingsboard.server.dao.asset.AssetSearchQuery; | |
43 | +import org.thingsboard.server.dao.asset.AssetService; | |
44 | +import org.thingsboard.server.dao.customer.CustomerDao; | |
45 | +import org.thingsboard.server.dao.entity.BaseEntityService; | |
46 | +import org.thingsboard.server.dao.exception.DataValidationException; | |
47 | +import org.thingsboard.server.dao.model.AlarmEntity; | |
48 | +import org.thingsboard.server.dao.model.AssetEntity; | |
49 | +import org.thingsboard.server.dao.model.CustomerEntity; | |
50 | +import org.thingsboard.server.dao.model.TenantEntity; | |
51 | +import org.thingsboard.server.dao.relation.EntityRelationsQuery; | |
52 | +import org.thingsboard.server.dao.relation.EntitySearchDirection; | |
53 | +import org.thingsboard.server.dao.relation.RelationService; | |
54 | +import org.thingsboard.server.dao.relation.RelationsSearchParameters; | |
55 | +import org.thingsboard.server.dao.service.DataValidator; | |
56 | +import org.thingsboard.server.dao.service.PaginatedRemover; | |
57 | +import org.thingsboard.server.dao.tenant.TenantDao; | |
58 | + | |
59 | +import javax.annotation.Nullable; | |
60 | +import java.util.ArrayList; | |
61 | +import java.util.Collections; | |
62 | +import java.util.List; | |
63 | +import java.util.Optional; | |
64 | +import java.util.concurrent.ExecutionException; | |
65 | +import java.util.stream.Collectors; | |
66 | + | |
67 | +import static org.thingsboard.server.dao.DaoUtil.*; | |
68 | +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; | |
69 | +import static org.thingsboard.server.dao.service.Validator.*; | |
70 | + | |
71 | +@Service | |
72 | +@Slf4j | |
73 | +public class BaseAlarmService extends BaseEntityService implements AlarmService { | |
74 | + | |
75 | + private static final String ALARM_RELATION_PREFIX = "ALARM_"; | |
76 | + private static final String ALARM_RELATION = "ALARM_ANY"; | |
77 | + | |
78 | + @Autowired | |
79 | + private AlarmDao alarmDao; | |
80 | + | |
81 | + @Autowired | |
82 | + private TenantDao tenantDao; | |
83 | + | |
84 | + @Autowired | |
85 | + private RelationService relationService; | |
86 | + | |
87 | + @Override | |
88 | + public Alarm createOrUpdateAlarm(Alarm alarm) { | |
89 | + alarmDataValidator.validate(alarm); | |
90 | + try { | |
91 | + if (alarm.getStartTs() == 0L) { | |
92 | + alarm.setStartTs(System.currentTimeMillis()); | |
93 | + } | |
94 | + Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get(); | |
95 | + if (existing == null || existing.getStatus().isCleared()) { | |
96 | + log.debug("New Alarm : {}", alarm); | |
97 | + Alarm saved = getData(alarmDao.save(new AlarmEntity(alarm))); | |
98 | + EntityRelationsQuery query = new EntityRelationsQuery(); | |
99 | + query.setParameters(new RelationsSearchParameters(saved.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE)); | |
100 | + List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList()); | |
101 | + for (EntityId parentId : parentEntities) { | |
102 | + createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION)); | |
103 | + createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name())); | |
104 | + } | |
105 | + return saved; | |
106 | + } else { | |
107 | + log.debug("Alarm before merge: {}", alarm); | |
108 | + alarm = merge(existing, alarm); | |
109 | + log.debug("Alarm after merge: {}", alarm); | |
110 | + return getData(alarmDao.save(new AlarmEntity(alarm))); | |
111 | + } | |
112 | + } catch (ExecutionException | InterruptedException e) { | |
113 | + throw new RuntimeException(e); | |
114 | + } | |
115 | + } | |
116 | + | |
117 | + @Override | |
118 | + public ListenableFuture<Boolean> updateAlarm(Alarm update) { | |
119 | + alarmDataValidator.validate(update); | |
120 | + return getAndUpdate(update.getId(), new Function<AlarmEntity, Boolean>() { | |
121 | + @Nullable | |
122 | + @Override | |
123 | + public Boolean apply(@Nullable AlarmEntity entity) { | |
124 | + Alarm alarm = getData(entity); | |
125 | + if (alarm == null) { | |
126 | + return false; | |
127 | + } else { | |
128 | + AlarmStatus oldStatus = alarm.getStatus(); | |
129 | + AlarmStatus newStatus = update.getStatus(); | |
130 | + alarmDao.save(new AlarmEntity(merge(alarm, update))); | |
131 | + if (oldStatus != newStatus) { | |
132 | + updateRelations(alarm, oldStatus, newStatus); | |
133 | + } | |
134 | + return true; | |
135 | + } | |
136 | + } | |
137 | + }); | |
138 | + } | |
139 | + | |
140 | + @Override | |
141 | + public ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTime) { | |
142 | + return getAndUpdate(alarmId, new Function<AlarmEntity, Boolean>() { | |
143 | + @Nullable | |
144 | + @Override | |
145 | + public Boolean apply(@Nullable AlarmEntity entity) { | |
146 | + Alarm alarm = getData(entity); | |
147 | + if (alarm == null || alarm.getStatus().isAck()) { | |
148 | + return false; | |
149 | + } else { | |
150 | + AlarmStatus oldStatus = alarm.getStatus(); | |
151 | + AlarmStatus newStatus = oldStatus.isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK; | |
152 | + alarm.setStatus(newStatus); | |
153 | + alarm.setAckTs(ackTime); | |
154 | + alarmDao.save(new AlarmEntity(alarm)); | |
155 | + updateRelations(alarm, oldStatus, newStatus); | |
156 | + return true; | |
157 | + } | |
158 | + } | |
159 | + }); | |
160 | + } | |
161 | + | |
162 | + @Override | |
163 | + public ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long clearTime) { | |
164 | + return getAndUpdate(alarmId, new Function<AlarmEntity, Boolean>() { | |
165 | + @Nullable | |
166 | + @Override | |
167 | + public Boolean apply(@Nullable AlarmEntity entity) { | |
168 | + Alarm alarm = getData(entity); | |
169 | + if (alarm == null || alarm.getStatus().isCleared()) { | |
170 | + return false; | |
171 | + } else { | |
172 | + AlarmStatus oldStatus = alarm.getStatus(); | |
173 | + AlarmStatus newStatus = oldStatus.isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK; | |
174 | + alarm.setStatus(newStatus); | |
175 | + alarm.setClearTs(clearTime); | |
176 | + alarmDao.save(new AlarmEntity(alarm)); | |
177 | + updateRelations(alarm, oldStatus, newStatus); | |
178 | + return true; | |
179 | + } | |
180 | + } | |
181 | + }); | |
182 | + } | |
183 | + | |
184 | + @Override | |
185 | + public ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query) { | |
186 | + return null; | |
187 | + } | |
188 | + | |
189 | + private void deleteRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException { | |
190 | + log.debug("Deleting Alarm relation: {}", alarmRelation); | |
191 | + relationService.deleteRelation(alarmRelation).get(); | |
192 | + } | |
193 | + | |
194 | + private void createRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException { | |
195 | + log.debug("Creating Alarm relation: {}", alarmRelation); | |
196 | + relationService.saveRelation(alarmRelation).get(); | |
197 | + } | |
198 | + | |
199 | + private Alarm merge(Alarm existing, Alarm alarm) { | |
200 | + if (alarm.getStartTs() > existing.getEndTs()) { | |
201 | + existing.setEndTs(alarm.getStartTs()); | |
202 | + } | |
203 | + if (alarm.getEndTs() > existing.getEndTs()) { | |
204 | + existing.setEndTs(alarm.getEndTs()); | |
205 | + } | |
206 | + if (alarm.getClearTs() > existing.getClearTs()) { | |
207 | + existing.setClearTs(alarm.getClearTs()); | |
208 | + } | |
209 | + if (alarm.getAckTs() > existing.getAckTs()) { | |
210 | + existing.setAckTs(alarm.getAckTs()); | |
211 | + } | |
212 | + existing.setStatus(alarm.getStatus()); | |
213 | + existing.setSeverity(alarm.getSeverity()); | |
214 | + existing.setDetails(alarm.getDetails()); | |
215 | + return existing; | |
216 | + } | |
217 | + | |
218 | + private void updateRelations(Alarm alarm, AlarmStatus oldStatus, AlarmStatus newStatus) { | |
219 | + try { | |
220 | + EntityRelationsQuery query = new EntityRelationsQuery(); | |
221 | + query.setParameters(new RelationsSearchParameters(alarm.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE)); | |
222 | + List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList()); | |
223 | + for (EntityId parentId : parentEntities) { | |
224 | + deleteRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + oldStatus.name())); | |
225 | + createRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + newStatus.name())); | |
226 | + } | |
227 | + } catch (ExecutionException | InterruptedException e) { | |
228 | + log.warn("[{}] Failed to update relations. Old status: [{}], New status: [{}]", alarm.getId(), oldStatus, newStatus); | |
229 | + throw new RuntimeException(e); | |
230 | + } | |
231 | + } | |
232 | + | |
233 | + private ListenableFuture<Boolean> getAndUpdate(AlarmId alarmId, Function<AlarmEntity, Boolean> function) { | |
234 | + validateId(alarmId, "Alarm id should be specified!"); | |
235 | + ListenableFuture<AlarmEntity> entity = alarmDao.findByIdAsync(alarmId.getId()); | |
236 | + return Futures.transform(entity, function); | |
237 | + } | |
238 | + | |
239 | + private DataValidator<Alarm> alarmDataValidator = | |
240 | + new DataValidator<Alarm>() { | |
241 | + | |
242 | + @Override | |
243 | + protected void validateDataImpl(Alarm alarm) { | |
244 | + if (StringUtils.isEmpty(alarm.getType())) { | |
245 | + throw new DataValidationException("Alarm type should be specified!"); | |
246 | + } | |
247 | + if (alarm.getOriginator() == null) { | |
248 | + throw new DataValidationException("Alarm originator should be specified!"); | |
249 | + } | |
250 | + if (alarm.getSeverity() == null) { | |
251 | + throw new DataValidationException("Alarm severity should be specified!"); | |
252 | + } | |
253 | + if (alarm.getStatus() == null) { | |
254 | + throw new DataValidationException("Alarm status should be specified!"); | |
255 | + } | |
256 | + if (alarm.getTenantId() == null) { | |
257 | + throw new DataValidationException("Alarm should be assigned to tenant!"); | |
258 | + } else { | |
259 | + TenantEntity tenant = tenantDao.findById(alarm.getTenantId().getId()); | |
260 | + if (tenant == null) { | |
261 | + throw new DataValidationException("Alarm is referencing to non-existent tenant!"); | |
262 | + } | |
263 | + } | |
264 | + } | |
265 | + }; | |
266 | +} | ... | ... |
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 | ... | ... |
... | ... | @@ -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; |
... | ... | @@ -91,6 +90,7 @@ public class DashboardServiceImpl implements DashboardService { |
91 | 90 | public void deleteDashboard(DashboardId dashboardId) { |
92 | 91 | log.trace("Executing deleteDashboard [{}]", dashboardId); |
93 | 92 | Validator.validateId(dashboardId, "Incorrect dashboardId " + dashboardId); |
93 | + deleteEntityRelations(dashboardId); | |
94 | 94 | dashboardDao.removeById(dashboardId.getId()); |
95 | 95 | } |
96 | 96 | ... | ... |
... | ... | @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.page.TextPageLink; |
32 | 32 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
33 | 33 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
34 | 34 | import org.thingsboard.server.dao.customer.CustomerDao; |
35 | +import org.thingsboard.server.dao.entity.BaseEntityService; | |
35 | 36 | import org.thingsboard.server.dao.exception.DataValidationException; |
36 | 37 | import org.thingsboard.server.dao.model.CustomerEntity; |
37 | 38 | import org.thingsboard.server.dao.model.DeviceEntity; |
... | ... | @@ -53,7 +54,7 @@ import static org.thingsboard.server.dao.service.Validator.validatePageLink; |
53 | 54 | |
54 | 55 | @Service |
55 | 56 | @Slf4j |
56 | -public class DeviceServiceImpl implements DeviceService { | |
57 | +public class DeviceServiceImpl extends BaseEntityService implements DeviceService { | |
57 | 58 | |
58 | 59 | @Autowired |
59 | 60 | private DeviceDao deviceDao; |
... | ... | @@ -132,6 +133,7 @@ public class DeviceServiceImpl implements DeviceService { |
132 | 133 | if (deviceCredentials != null) { |
133 | 134 | deviceCredentialsService.deleteDeviceCredentials(deviceCredentials); |
134 | 135 | } |
136 | + deleteEntityRelations(deviceId); | |
135 | 137 | deviceDao.removeById(deviceId.getId()); |
136 | 138 | } |
137 | 139 | ... | ... |
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.*; | |
20 | +import com.fasterxml.jackson.databind.JsonNode; | |
21 | +import org.thingsboard.server.common.data.EntityType; | |
22 | +import org.thingsboard.server.common.data.alarm.Alarm; | |
23 | +import org.thingsboard.server.common.data.alarm.AlarmId; | |
24 | +import org.thingsboard.server.common.data.alarm.AlarmSeverity; | |
25 | +import org.thingsboard.server.common.data.alarm.AlarmStatus; | |
26 | +import org.thingsboard.server.common.data.id.EntityIdFactory; | |
27 | +import org.thingsboard.server.common.data.id.TenantId; | |
28 | +import org.thingsboard.server.dao.model.type.AlarmSeverityCodec; | |
29 | +import org.thingsboard.server.dao.model.type.AlarmStatusCodec; | |
30 | +import org.thingsboard.server.dao.model.type.EntityTypeCodec; | |
31 | +import org.thingsboard.server.dao.model.type.JsonCodec; | |
32 | + | |
33 | +import java.util.UUID; | |
34 | + | |
35 | +import static org.thingsboard.server.dao.model.ModelConstants.*; | |
36 | + | |
37 | +@Table(name = ALARM_COLUMN_FAMILY_NAME) | |
38 | +public final class AlarmEntity implements BaseEntity<Alarm> { | |
39 | + | |
40 | + @Transient | |
41 | + private static final long serialVersionUID = -1265181166886910152L; | |
42 | + | |
43 | + @ClusteringColumn(value = 1) | |
44 | + @Column(name = ID_PROPERTY) | |
45 | + private UUID id; | |
46 | + | |
47 | + @PartitionKey(value = 0) | |
48 | + @Column(name = ALARM_TENANT_ID_PROPERTY) | |
49 | + private UUID tenantId; | |
50 | + | |
51 | + @PartitionKey(value = 1) | |
52 | + @Column(name = ALARM_ORIGINATOR_ID_PROPERTY) | |
53 | + private UUID originatorId; | |
54 | + | |
55 | + @PartitionKey(value = 2) | |
56 | + @Column(name = ALARM_ORIGINATOR_TYPE_PROPERTY, codec = EntityTypeCodec.class) | |
57 | + private EntityType originatorType; | |
58 | + | |
59 | + @ClusteringColumn(value = 0) | |
60 | + @Column(name = ALARM_TYPE_PROPERTY) | |
61 | + private String type; | |
62 | + | |
63 | + @Column(name = ALARM_SEVERITY_PROPERTY, codec = AlarmSeverityCodec.class) | |
64 | + private AlarmSeverity severity; | |
65 | + | |
66 | + @Column(name = ALARM_STATUS_PROPERTY, codec = AlarmStatusCodec.class) | |
67 | + private AlarmStatus status; | |
68 | + | |
69 | + @Column(name = ALARM_START_TS_PROPERTY) | |
70 | + private Long startTs; | |
71 | + | |
72 | + @Column(name = ALARM_END_TS_PROPERTY) | |
73 | + private Long endTs; | |
74 | + | |
75 | + @Column(name = ALARM_ACK_TS_PROPERTY) | |
76 | + private Long ackTs; | |
77 | + | |
78 | + @Column(name = ALARM_CLEAR_TS_PROPERTY) | |
79 | + private Long clearTs; | |
80 | + | |
81 | + @Column(name = ALARM_DETAILS_PROPERTY, codec = JsonCodec.class) | |
82 | + private JsonNode details; | |
83 | + | |
84 | + @Column(name = ALARM_PROPAGATE_PROPERTY) | |
85 | + private Boolean propagate; | |
86 | + | |
87 | + public AlarmEntity() { | |
88 | + super(); | |
89 | + } | |
90 | + | |
91 | + public AlarmEntity(Alarm alarm) { | |
92 | + if (alarm.getId() != null) { | |
93 | + this.id = alarm.getId().getId(); | |
94 | + } | |
95 | + if (alarm.getTenantId() != null) { | |
96 | + this.tenantId = alarm.getTenantId().getId(); | |
97 | + } | |
98 | + this.type = alarm.getType(); | |
99 | + this.originatorId = alarm.getOriginator().getId(); | |
100 | + this.originatorType = alarm.getOriginator().getEntityType(); | |
101 | + this.type = alarm.getType(); | |
102 | + this.severity = alarm.getSeverity(); | |
103 | + this.status = alarm.getStatus(); | |
104 | + this.propagate = alarm.isPropagate(); | |
105 | + this.startTs = alarm.getStartTs(); | |
106 | + this.endTs = alarm.getEndTs(); | |
107 | + this.ackTs = alarm.getAckTs(); | |
108 | + this.clearTs = alarm.getClearTs(); | |
109 | + this.details = alarm.getDetails(); | |
110 | + } | |
111 | + | |
112 | + public UUID getId() { | |
113 | + return id; | |
114 | + } | |
115 | + | |
116 | + public void setId(UUID id) { | |
117 | + this.id = id; | |
118 | + } | |
119 | + | |
120 | + public UUID getTenantId() { | |
121 | + return tenantId; | |
122 | + } | |
123 | + | |
124 | + public void setTenantId(UUID tenantId) { | |
125 | + this.tenantId = tenantId; | |
126 | + } | |
127 | + | |
128 | + @Override | |
129 | + public Alarm toData() { | |
130 | + Alarm alarm = new Alarm(new AlarmId(id)); | |
131 | + alarm.setCreatedTime(UUIDs.unixTimestamp(id)); | |
132 | + if (tenantId != null) { | |
133 | + alarm.setTenantId(new TenantId(tenantId)); | |
134 | + } | |
135 | + alarm.setOriginator(EntityIdFactory.getByTypeAndUuid(originatorType, originatorId)); | |
136 | + alarm.setType(type); | |
137 | + alarm.setSeverity(severity); | |
138 | + alarm.setStatus(status); | |
139 | + alarm.setPropagate(propagate); | |
140 | + alarm.setStartTs(startTs); | |
141 | + alarm.setEndTs(endTs); | |
142 | + alarm.setAckTs(ackTs); | |
143 | + alarm.setClearTs(clearTs); | |
144 | + alarm.setDetails(details); | |
145 | + return alarm; | |
146 | + } | |
147 | + | |
148 | +} | |
\ No newline at end of file | ... | ... |
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 | ... | ... |
... | ... | @@ -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); | ... | ... |
... | ... | @@ -126,6 +126,49 @@ public class ModelConstants { |
126 | 126 | public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text"; |
127 | 127 | public static final String DEVICE_BY_TENANT_AND_NAME_VIEW_NAME = "device_by_tenant_and_name"; |
128 | 128 | |
129 | + /** | |
130 | + * Cassandra asset constants. | |
131 | + */ | |
132 | + public static final String ASSET_COLUMN_FAMILY_NAME = "asset"; | |
133 | + public static final String ASSET_TENANT_ID_PROPERTY = TENTANT_ID_PROPERTY; | |
134 | + public static final String ASSET_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; | |
135 | + public static final String ASSET_NAME_PROPERTY = "name"; | |
136 | + public static final String ASSET_TYPE_PROPERTY = "type"; | |
137 | + public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; | |
138 | + | |
139 | + public static final String ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_and_search_text"; | |
140 | + public static final String ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_customer_and_search_text"; | |
141 | + public static final String ASSET_BY_TENANT_AND_NAME_VIEW_NAME = "asset_by_tenant_and_name"; | |
142 | + | |
143 | + /** | |
144 | + * Cassandra alarm constants. | |
145 | + */ | |
146 | + public static final String ALARM_COLUMN_FAMILY_NAME = "alarm"; | |
147 | + public static final String ALARM_TENANT_ID_PROPERTY = TENTANT_ID_PROPERTY; | |
148 | + public static final String ALARM_TYPE_PROPERTY = "type"; | |
149 | + public static final String ALARM_DETAILS_PROPERTY = "details"; | |
150 | + public static final String ALARM_ORIGINATOR_ID_PROPERTY = "originator_id"; | |
151 | + public static final String ALARM_ORIGINATOR_TYPE_PROPERTY = "originator_type"; | |
152 | + public static final String ALARM_SEVERITY_PROPERTY = "severity"; | |
153 | + public static final String ALARM_STATUS_PROPERTY = "status"; | |
154 | + public static final String ALARM_START_TS_PROPERTY = "start_ts"; | |
155 | + public static final String ALARM_END_TS_PROPERTY = "end_ts"; | |
156 | + public static final String ALARM_ACK_TS_PROPERTY = "ack_ts"; | |
157 | + public static final String ALARM_CLEAR_TS_PROPERTY = "clear_ts"; | |
158 | + public static final String ALARM_PROPAGATE_PROPERTY = "propagate"; | |
159 | + | |
160 | + /** | |
161 | + * Cassandra entity relation constants. | |
162 | + */ | |
163 | + public static final String RELATION_COLUMN_FAMILY_NAME = "relation"; | |
164 | + public static final String RELATION_FROM_ID_PROPERTY = "from_id"; | |
165 | + public static final String RELATION_FROM_TYPE_PROPERTY = "from_type"; | |
166 | + public static final String RELATION_TO_ID_PROPERTY = "to_id"; | |
167 | + public static final String RELATION_TO_TYPE_PROPERTY = "to_type"; | |
168 | + public static final String RELATION_TYPE_PROPERTY = "relation_type"; | |
169 | + | |
170 | + public static final String RELATION_REVERSE_VIEW_NAME = "reverse_relation"; | |
171 | + | |
129 | 172 | |
130 | 173 | /** |
131 | 174 | * Cassandra device_credentials constants. | ... | ... |
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.type; | |
17 | + | |
18 | +import com.datastax.driver.extras.codecs.enums.EnumNameCodec; | |
19 | +import org.thingsboard.server.common.data.alarm.AlarmSeverity; | |
20 | +import org.thingsboard.server.common.data.alarm.AlarmStatus; | |
21 | +import org.thingsboard.server.dao.alarm.AlarmService; | |
22 | + | |
23 | +public class AlarmSeverityCodec extends EnumNameCodec<AlarmSeverity> { | |
24 | + | |
25 | + public AlarmSeverityCodec() { | |
26 | + super(AlarmSeverity.class); | |
27 | + } | |
28 | + | |
29 | +} | ... | ... |
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.type; | |
17 | + | |
18 | +import com.datastax.driver.extras.codecs.enums.EnumNameCodec; | |
19 | +import org.thingsboard.server.common.data.alarm.AlarmStatus; | |
20 | + | |
21 | +public class AlarmStatusCodec extends EnumNameCodec<AlarmStatus> { | |
22 | + | |
23 | + public AlarmStatusCodec() { | |
24 | + super(AlarmStatus.class); | |
25 | + } | |
26 | + | |
27 | +} | ... | ... |
... | ... | @@ -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.debug("Filters are not set [{}]", query); | |
132 | + } | |
133 | + | |
134 | + int maxLvl = params.getMaxLevel() > 0 ? params.getMaxLevel() : Integer.MAX_VALUE; | |
135 | + | |
136 | + try { | |
137 | + ListenableFuture<Set<EntityRelation>> relationSet = findRelationsRecursively(params.getEntityId(), params.getDirection(), maxLvl, new ConcurrentHashMap<>()); | |
138 | + return Futures.transform(relationSet, (Function<Set<EntityRelation>, List<EntityRelation>>) input -> { | |
139 | + List<EntityRelation> relations = new ArrayList<>(); | |
140 | + for (EntityRelation relation : input) { | |
141 | + if (filters == null || filters.isEmpty()) { | |
142 | + relations.add(relation); | |
143 | + } else { | |
144 | + for (EntityTypeFilter filter : filters) { | |
145 | + if (match(filter, relation, params.getDirection())) { | |
146 | + relations.add(relation); | |
147 | + break; | |
148 | + } | |
149 | + } | |
150 | + } | |
151 | + } | |
152 | + return relations; | |
153 | + }); | |
154 | + } catch (Exception e) { | |
155 | + log.warn("Failed to query relations: [{}]", query, e); | |
156 | + throw new RuntimeException(e); | |
157 | + } | |
158 | + } | |
159 | + | |
160 | + protected void validate(EntityRelation relation) { | |
161 | + if (relation == null) { | |
162 | + throw new DataValidationException("Relation type should be specified!"); | |
163 | + } | |
164 | + validate(relation.getFrom(), relation.getTo(), relation.getType()); | |
165 | + } | |
166 | + | |
167 | + protected void validate(EntityId from, EntityId to, String type) { | |
168 | + validateType(type); | |
169 | + if (from == null) { | |
170 | + throw new DataValidationException("Relation should contain from entity!"); | |
171 | + } | |
172 | + if (to == null) { | |
173 | + throw new DataValidationException("Relation should contain to entity!"); | |
174 | + } | |
175 | + } | |
176 | + | |
177 | + private void validateType(String type) { | |
178 | + if (StringUtils.isEmpty(type)) { | |
179 | + throw new DataValidationException("Relation type should be specified!"); | |
180 | + } | |
181 | + } | |
182 | + | |
183 | + protected void validate(EntityId entity) { | |
184 | + if (entity == null) { | |
185 | + throw new DataValidationException("Entity should be specified!"); | |
186 | + } | |
187 | + } | |
188 | + | |
189 | + private Function<List<Boolean>, Boolean> getListToBooleanFunction() { | |
190 | + return new Function<List<Boolean>, Boolean>() { | |
191 | + @Nullable | |
192 | + @Override | |
193 | + public Boolean apply(@Nullable List<Boolean> results) { | |
194 | + for (Boolean result : results) { | |
195 | + if (result == null || !result) { | |
196 | + return false; | |
197 | + } | |
198 | + } | |
199 | + return true; | |
200 | + } | |
201 | + }; | |
202 | + } | |
203 | + | |
204 | + private boolean match(EntityTypeFilter filter, EntityRelation relation, EntitySearchDirection direction) { | |
205 | + if (StringUtils.isEmpty(filter.getRelationType()) || filter.getRelationType().equals(relation.getType())) { | |
206 | + if (filter.getEntityTypes() == null || filter.getEntityTypes().isEmpty()) { | |
207 | + return true; | |
208 | + } else { | |
209 | + EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom(); | |
210 | + return filter.getEntityTypes().contains(entityId.getEntityType()); | |
211 | + } | |
212 | + } else { | |
213 | + return false; | |
214 | + } | |
215 | + } | |
216 | + | |
217 | + private ListenableFuture<Set<EntityRelation>> findRelationsRecursively(final EntityId rootId, final EntitySearchDirection direction, int lvl, | |
218 | + final ConcurrentHashMap<EntityId, Boolean> uniqueMap) throws Exception { | |
219 | + if (lvl == 0) { | |
220 | + return Futures.immediateFuture(Collections.emptySet()); | |
221 | + } | |
222 | + lvl--; | |
223 | + //TODO: try to remove this blocking operation | |
224 | + Set<EntityRelation> children = new HashSet<>(findRelations(rootId, direction).get()); | |
225 | + Set<EntityId> childrenIds = new HashSet<>(); | |
226 | + for (EntityRelation childRelation : children) { | |
227 | + log.info("Found Relation: {}", childRelation); | |
228 | + EntityId childId; | |
229 | + if (direction == EntitySearchDirection.FROM) { | |
230 | + childId = childRelation.getTo(); | |
231 | + } else { | |
232 | + childId = childRelation.getFrom(); | |
233 | + } | |
234 | + if (uniqueMap.putIfAbsent(childId, Boolean.TRUE) == null) { | |
235 | + log.info("Adding Relation: {}", childId); | |
236 | + if (childrenIds.add(childId)) { | |
237 | + log.info("Added Relation: {}", childId); | |
238 | + } | |
239 | + } | |
240 | + } | |
241 | + List<ListenableFuture<Set<EntityRelation>>> futures = new ArrayList<>(); | |
242 | + for (EntityId entityId : childrenIds) { | |
243 | + futures.add(findRelationsRecursively(entityId, direction, lvl, uniqueMap)); | |
244 | + } | |
245 | + //TODO: try to remove this blocking operation | |
246 | + List<Set<EntityRelation>> relations = Futures.successfulAsList(futures).get(); | |
247 | + relations.forEach(r -> r.forEach(d -> children.add(d))); | |
248 | + return Futures.immediateFuture(children); | |
249 | + } | |
250 | + | |
251 | + private ListenableFuture<List<EntityRelation>> findRelations(final EntityId rootId, final EntitySearchDirection direction) { | |
252 | + ListenableFuture<List<EntityRelation>> relations; | |
253 | + if (direction == EntitySearchDirection.FROM) { | |
254 | + relations = findByFrom(rootId); | |
255 | + } else { | |
256 | + relations = findByTo(rootId); | |
257 | + } | |
258 | + return relations; | |
259 | + } | |
260 | + | |
261 | +} | ... | ... |
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 | +// TODO: This method may be useful for some validations in the future | |
50 | +// ListenableFuture<Boolean> checkRecursiveRelation(EntityId from, EntityId to); | |
51 | + | |
52 | +} | ... | ... |
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); | ... | ... |