Commit 0758b6643c56a2af888f6c3d1dc0e227bcbae6de

Authored by Volodymyr Babak
2 parents 2b18ed7a 750c4750

Merge branch 'master' into feature/kubernetes

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 }
  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");
  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 }
  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);