Commit 0f85e164462821f22854310fe53360854b2d31a2

Authored by Andrew Shvayka
1 parent 0a0b0248

Asset and Relations management, Dashboard states and layouts management

Showing 69 changed files with 3473 additions and 214 deletions

Too many changes to show.

To preserve performance only 69 of 225 files are displayed.

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