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