248 changed files with 14989 additions and 2081 deletions
@ -0,0 +1,234 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.controller; |
|||
|
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.asset.AssetSearchQuery; |
|||
import org.thingsboard.server.dao.exception.IncorrectParameterException; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class AssetController extends BaseController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/asset/{assetId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public Asset getAssetById(@PathVariable("assetId") String strAssetId) throws ThingsboardException { |
|||
checkParameter("assetId", strAssetId); |
|||
try { |
|||
AssetId assetId = new AssetId(toUUID(strAssetId)); |
|||
return checkAssetId(assetId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/asset", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public Asset saveAsset(@RequestBody Asset asset) throws ThingsboardException { |
|||
try { |
|||
asset.setTenantId(getCurrentUser().getTenantId()); |
|||
return checkNotNull(assetService.saveAsset(asset)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/asset/{assetId}", method = RequestMethod.DELETE) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteAsset(@PathVariable("assetId") String strAssetId) throws ThingsboardException { |
|||
checkParameter("assetId", strAssetId); |
|||
try { |
|||
AssetId assetId = new AssetId(toUUID(strAssetId)); |
|||
checkAssetId(assetId); |
|||
assetService.deleteAsset(assetId); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/customer/{customerId}/asset/{assetId}", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public Asset assignAssetToCustomer(@PathVariable("customerId") String strCustomerId, |
|||
@PathVariable("assetId") String strAssetId) throws ThingsboardException { |
|||
checkParameter("customerId", strCustomerId); |
|||
checkParameter("assetId", strAssetId); |
|||
try { |
|||
CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
|||
checkCustomerId(customerId); |
|||
|
|||
AssetId assetId = new AssetId(toUUID(strAssetId)); |
|||
checkAssetId(assetId); |
|||
|
|||
return checkNotNull(assetService.assignAssetToCustomer(assetId, customerId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/customer/asset/{assetId}", method = RequestMethod.DELETE) |
|||
@ResponseBody |
|||
public Asset unassignAssetFromCustomer(@PathVariable("assetId") String strAssetId) throws ThingsboardException { |
|||
checkParameter("assetId", strAssetId); |
|||
try { |
|||
AssetId assetId = new AssetId(toUUID(strAssetId)); |
|||
Asset asset = checkAssetId(assetId); |
|||
if (asset.getCustomerId() == null || asset.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { |
|||
throw new IncorrectParameterException("Asset isn't assigned to any customer!"); |
|||
} |
|||
return checkNotNull(assetService.unassignAssetFromCustomer(assetId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/customer/public/asset/{assetId}", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public Asset assignAssetToPublicCustomer(@PathVariable("assetId") String strAssetId) throws ThingsboardException { |
|||
checkParameter("assetId", strAssetId); |
|||
try { |
|||
AssetId assetId = new AssetId(toUUID(strAssetId)); |
|||
Asset asset = checkAssetId(assetId); |
|||
Customer publicCustomer = customerService.findOrCreatePublicCustomer(asset.getTenantId()); |
|||
return checkNotNull(assetService.assignAssetToCustomer(assetId, publicCustomer.getId())); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/tenant/assets", params = {"limit"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<Asset> getTenantAssets( |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
try { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/tenant/assets", params = {"assetName"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public Asset getTenantAsset( |
|||
@RequestParam String assetName) throws ThingsboardException { |
|||
try { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
return checkNotNull(assetService.findAssetByTenantIdAndName(tenantId, assetName)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/customer/{customerId}/assets", params = {"limit"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public TextPageData<Asset> getCustomerAssets( |
|||
@PathVariable("customerId") String strCustomerId, |
|||
@RequestParam int limit, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String idOffset, |
|||
@RequestParam(required = false) String textOffset) throws ThingsboardException { |
|||
checkParameter("customerId", strCustomerId); |
|||
try { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
|||
checkCustomerId(customerId); |
|||
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
|||
return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/assets", params = {"assetIds"}, method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public List<Asset> getAssetsByIds( |
|||
@RequestParam("assetIds") String[] strAssetIds) throws ThingsboardException { |
|||
checkArrayParameter("assetIds", strAssetIds); |
|||
try { |
|||
SecurityUser user = getCurrentUser(); |
|||
TenantId tenantId = user.getTenantId(); |
|||
CustomerId customerId = user.getCustomerId(); |
|||
List<AssetId> assetIds = new ArrayList<>(); |
|||
for (String strAssetId : strAssetIds) { |
|||
assetIds.add(new AssetId(toUUID(strAssetId))); |
|||
} |
|||
ListenableFuture<List<Asset>> assets; |
|||
if (customerId == null || customerId.isNullUid()) { |
|||
assets = assetService.findAssetsByTenantIdAndIdsAsync(tenantId, assetIds); |
|||
} else { |
|||
assets = assetService.findAssetsByTenantIdCustomerIdAndIdsAsync(tenantId, customerId, assetIds); |
|||
} |
|||
return checkNotNull(assets.get()); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/assets", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public List<Asset> findByQuery(@RequestBody AssetSearchQuery query) throws ThingsboardException { |
|||
checkNotNull(query); |
|||
checkNotNull(query.getParameters()); |
|||
checkNotNull(query.getAssetTypes()); |
|||
checkEntityId(query.getParameters().getEntityId()); |
|||
try { |
|||
List<Asset> assets = checkNotNull(assetService.findAssetsByQuery(query).get()); |
|||
assets = assets.stream().filter(asset -> { |
|||
try { |
|||
checkAsset(asset); |
|||
return true; |
|||
} catch (ThingsboardException e) { |
|||
return false; |
|||
} |
|||
}).collect(Collectors.toList()); |
|||
return assets; |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,194 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.controller; |
|||
|
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|||
import org.thingsboard.server.common.data.relation.EntityRelation; |
|||
import org.thingsboard.server.dao.relation.EntityRelationsQuery; |
|||
import org.thingsboard.server.exception.ThingsboardErrorCode; |
|||
import org.thingsboard.server.exception.ThingsboardException; |
|||
|
|||
import java.util.List; |
|||
|
|||
|
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class EntityRelationController extends BaseController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/relation", method = RequestMethod.POST) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void saveRelation(@RequestBody EntityRelation relation) throws ThingsboardException { |
|||
try { |
|||
checkNotNull(relation); |
|||
checkEntityId(relation.getFrom()); |
|||
checkEntityId(relation.getTo()); |
|||
relationService.saveRelation(relation).get(); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/relation", method = RequestMethod.DELETE, params = {"fromId", "fromType", "relationType", "toId", "toType"}) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteRelation(@RequestParam("fromId") String strFromId, |
|||
@RequestParam("fromType") String strFromType, @RequestParam("relationType") String strRelationType, |
|||
@RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException { |
|||
checkParameter("fromId", strFromId); |
|||
checkParameter("fromType", strFromType); |
|||
checkParameter("relationType", strRelationType); |
|||
checkParameter("toId", strToId); |
|||
checkParameter("toType", strToType); |
|||
EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); |
|||
EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId); |
|||
checkEntityId(fromId); |
|||
checkEntityId(toId); |
|||
try { |
|||
Boolean found = relationService.deleteRelation(fromId, toId, strRelationType).get(); |
|||
if (!found) { |
|||
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); |
|||
} |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/relations", method = RequestMethod.DELETE, params = {"id", "type"}) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void deleteRelations(@RequestParam("entityId") String strId, |
|||
@RequestParam("entityType") String strType) throws ThingsboardException { |
|||
checkParameter("entityId", strId); |
|||
checkParameter("entityType", strType); |
|||
EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId); |
|||
checkEntityId(entityId); |
|||
try { |
|||
relationService.deleteEntityRelations(entityId).get(); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/relation", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType", "toId", "toType"}) |
|||
@ResponseStatus(value = HttpStatus.OK) |
|||
public void checkRelation(@RequestParam("fromId") String strFromId, |
|||
@RequestParam("fromType") String strFromType, @RequestParam("relationType") String strRelationType, |
|||
@RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException { |
|||
try { |
|||
checkParameter("fromId", strFromId); |
|||
checkParameter("fromType", strFromType); |
|||
checkParameter("relationType", strRelationType); |
|||
checkParameter("toId", strToId); |
|||
checkParameter("toType", strToType); |
|||
EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); |
|||
EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId); |
|||
checkEntityId(fromId); |
|||
checkEntityId(toId); |
|||
Boolean found = relationService.checkRelation(fromId, toId, strRelationType).get(); |
|||
if (!found) { |
|||
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); |
|||
} |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType"}) |
|||
@ResponseBody |
|||
public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType) throws ThingsboardException { |
|||
checkParameter("fromId", strFromId); |
|||
checkParameter("fromType", strFromType); |
|||
EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); |
|||
checkEntityId(entityId); |
|||
try { |
|||
return checkNotNull(relationService.findByFrom(entityId).get()); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType"}) |
|||
@ResponseBody |
|||
public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType |
|||
, @RequestParam("relationType") String strRelationType) throws ThingsboardException { |
|||
checkParameter("fromId", strFromId); |
|||
checkParameter("fromType", strFromType); |
|||
checkParameter("relationType", strRelationType); |
|||
EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); |
|||
checkEntityId(entityId); |
|||
try { |
|||
return checkNotNull(relationService.findByFromAndType(entityId, strRelationType).get()); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType"}) |
|||
@ResponseBody |
|||
public List<EntityRelation> findByTo(@RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException { |
|||
checkParameter("toId", strToId); |
|||
checkParameter("toType", strToType); |
|||
EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId); |
|||
checkEntityId(entityId); |
|||
try { |
|||
return checkNotNull(relationService.findByTo(entityId).get()); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType", "relationType"}) |
|||
@ResponseBody |
|||
public List<EntityRelation> findByTo(@RequestParam("toId") String strToId, @RequestParam("toType") String strToType |
|||
, @RequestParam("relationType") String strRelationType) throws ThingsboardException { |
|||
checkParameter("toId", strToId); |
|||
checkParameter("toType", strToType); |
|||
checkParameter("relationType", strRelationType); |
|||
EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId); |
|||
checkEntityId(entityId); |
|||
try { |
|||
return checkNotNull(relationService.findByToAndType(entityId, strRelationType).get()); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/relations", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public List<EntityRelation> findByQuery(@RequestBody EntityRelationsQuery query) throws ThingsboardException { |
|||
checkNotNull(query); |
|||
checkNotNull(query.getParameters()); |
|||
checkNotNull(query.getFilters()); |
|||
checkEntityId(query.getParameters().getEntityId()); |
|||
try { |
|||
return checkNotNull(relationService.findByQuery(query).get()); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.alarm; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.BaseData; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
|
|||
/** |
|||
* Created by ashvayka on 11.05.17. |
|||
*/ |
|||
@Data |
|||
public class Alarm extends BaseData<AlarmId> { |
|||
|
|||
private long startTs; |
|||
private long endTs; |
|||
private long ackTs; |
|||
private long clearTs; |
|||
private String type; |
|||
private EntityId originator; |
|||
private AlarmSeverity severity; |
|||
private AlarmStatus status; |
|||
private JsonNode details; |
|||
private boolean propagate; |
|||
|
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.alarm; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonCreator; |
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import com.fasterxml.jackson.annotation.JsonProperty; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.UUIDBased; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
public class AlarmId extends UUIDBased implements EntityId { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
@JsonCreator |
|||
public AlarmId(@JsonProperty("id") UUID id) { |
|||
super(id); |
|||
} |
|||
|
|||
public static AlarmId fromString(String alarmId) { |
|||
return new AlarmId(UUID.fromString(alarmId)); |
|||
} |
|||
|
|||
@JsonIgnore |
|||
@Override |
|||
public EntityType getEntityType() { |
|||
return EntityType.ALARM; |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.alarm; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.page.TimePageLink; |
|||
|
|||
/** |
|||
* Created by ashvayka on 11.05.17. |
|||
*/ |
|||
@Data |
|||
public class AlarmQuery { |
|||
|
|||
private EntityId affectedEntityId; |
|||
private TimePageLink pageLink; |
|||
private AlarmStatus status; |
|||
|
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.alarm; |
|||
|
|||
/** |
|||
* Created by ashvayka on 11.05.17. |
|||
*/ |
|||
public enum AlarmSeverity { |
|||
|
|||
CRITICAL, MAJOR, MINOR, WARNING, INDETERMINATE; |
|||
|
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.alarm; |
|||
|
|||
/** |
|||
* Created by ashvayka on 11.05.17. |
|||
*/ |
|||
public enum AlarmStatus { |
|||
|
|||
ACTIVE_UNACK, ACTIVE_ACK, CLEARED_UNACK, CLEARED_ACK; |
|||
|
|||
} |
|||
@ -0,0 +1,166 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.asset; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import org.thingsboard.server.common.data.SearchTextBased; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
|
|||
public class Asset extends SearchTextBased<AssetId> { |
|||
|
|||
private static final long serialVersionUID = 2807343040519543363L; |
|||
|
|||
private TenantId tenantId; |
|||
private CustomerId customerId; |
|||
private String name; |
|||
private String type; |
|||
private JsonNode additionalInfo; |
|||
|
|||
public Asset() { |
|||
super(); |
|||
} |
|||
|
|||
public Asset(AssetId id) { |
|||
super(id); |
|||
} |
|||
|
|||
public Asset(Asset asset) { |
|||
super(asset); |
|||
this.tenantId = asset.getTenantId(); |
|||
this.customerId = asset.getCustomerId(); |
|||
this.name = asset.getName(); |
|||
this.type = asset.getType(); |
|||
this.additionalInfo = asset.getAdditionalInfo(); |
|||
} |
|||
|
|||
public TenantId getTenantId() { |
|||
return tenantId; |
|||
} |
|||
|
|||
public void setTenantId(TenantId tenantId) { |
|||
this.tenantId = tenantId; |
|||
} |
|||
|
|||
public CustomerId getCustomerId() { |
|||
return customerId; |
|||
} |
|||
|
|||
public void setCustomerId(CustomerId customerId) { |
|||
this.customerId = customerId; |
|||
} |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
public void setName(String name) { |
|||
this.name = name; |
|||
} |
|||
|
|||
public String getType() { |
|||
return type; |
|||
} |
|||
|
|||
public void setType(String type) { |
|||
this.type = type; |
|||
} |
|||
|
|||
public JsonNode getAdditionalInfo() { |
|||
return additionalInfo; |
|||
} |
|||
|
|||
public void setAdditionalInfo(JsonNode additionalInfo) { |
|||
this.additionalInfo = additionalInfo; |
|||
} |
|||
|
|||
@Override |
|||
public String getSearchText() { |
|||
return name; |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
final int prime = 31; |
|||
int result = super.hashCode(); |
|||
result = prime * result + ((additionalInfo == null) ? 0 : additionalInfo.hashCode()); |
|||
result = prime * result + ((customerId == null) ? 0 : customerId.hashCode()); |
|||
result = prime * result + ((name == null) ? 0 : name.hashCode()); |
|||
result = prime * result + ((type == null) ? 0 : type.hashCode()); |
|||
result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode()); |
|||
return result; |
|||
} |
|||
|
|||
@Override |
|||
public boolean equals(Object obj) { |
|||
if (this == obj) |
|||
return true; |
|||
if (!super.equals(obj)) |
|||
return false; |
|||
if (getClass() != obj.getClass()) |
|||
return false; |
|||
Asset other = (Asset) obj; |
|||
if (additionalInfo == null) { |
|||
if (other.additionalInfo != null) |
|||
return false; |
|||
} else if (!additionalInfo.equals(other.additionalInfo)) |
|||
return false; |
|||
if (customerId == null) { |
|||
if (other.customerId != null) |
|||
return false; |
|||
} else if (!customerId.equals(other.customerId)) |
|||
return false; |
|||
if (name == null) { |
|||
if (other.name != null) |
|||
return false; |
|||
} else if (!name.equals(other.name)) |
|||
return false; |
|||
if (type == null) { |
|||
if (other.type != null) |
|||
return false; |
|||
} else if (!type.equals(other.type)) |
|||
return false; |
|||
if (tenantId == null) { |
|||
if (other.tenantId != null) |
|||
return false; |
|||
} else if (!tenantId.equals(other.tenantId)) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
StringBuilder builder = new StringBuilder(); |
|||
builder.append("Asset [tenantId="); |
|||
builder.append(tenantId); |
|||
builder.append(", customerId="); |
|||
builder.append(customerId); |
|||
builder.append(", name="); |
|||
builder.append(name); |
|||
builder.append(", type="); |
|||
builder.append(type); |
|||
builder.append(", additionalInfo="); |
|||
builder.append(additionalInfo); |
|||
builder.append(", createdTime="); |
|||
builder.append(createdTime); |
|||
builder.append(", id="); |
|||
builder.append(id); |
|||
builder.append("]"); |
|||
return builder.toString(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.id; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonCreator; |
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import com.fasterxml.jackson.annotation.JsonProperty; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
public class AssetId extends UUIDBased implements EntityId { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
@JsonCreator |
|||
public AssetId(@JsonProperty("id") UUID id) { |
|||
super(id); |
|||
} |
|||
|
|||
public static AssetId fromString(String assetId) { |
|||
return new AssetId(UUID.fromString(assetId)); |
|||
} |
|||
|
|||
@JsonIgnore |
|||
@Override |
|||
public EntityType getEntityType() { |
|||
return EntityType.ASSET; |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.id; |
|||
|
|||
import com.fasterxml.jackson.core.JsonParser; |
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import com.fasterxml.jackson.core.ObjectCodec; |
|||
import com.fasterxml.jackson.databind.DeserializationContext; |
|||
import com.fasterxml.jackson.databind.JsonDeserializer; |
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* Created by ashvayka on 11.05.17. |
|||
*/ |
|||
public class EntityIdDeserializer extends JsonDeserializer<EntityId> { |
|||
|
|||
@Override |
|||
public EntityId deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException, JsonProcessingException { |
|||
ObjectCodec oc = jsonParser.getCodec(); |
|||
ObjectNode node = oc.readTree(jsonParser); |
|||
if (node.has("entityType") && node.has("id")) { |
|||
return EntityIdFactory.getByTypeAndId(node.get("entityType").asText(), node.get("id").asText()); |
|||
} else { |
|||
throw new IOException("Missing entityType or id!"); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.id; |
|||
|
|||
import org.thingsboard.server.common.data.EntityType; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
/** |
|||
* Created by ashvayka on 25.04.17. |
|||
*/ |
|||
public class EntityIdFactory { |
|||
|
|||
public static EntityId getByTypeAndId(String type, String uuid) { |
|||
return getByTypeAndUuid(EntityType.valueOf(type), UUID.fromString(uuid)); |
|||
} |
|||
|
|||
public static EntityId getByTypeAndUuid(String type, UUID uuid) { |
|||
return getByTypeAndUuid(EntityType.valueOf(type), uuid); |
|||
} |
|||
|
|||
public static EntityId getByTypeAndUuid(EntityType type, UUID uuid) { |
|||
switch (type) { |
|||
case TENANT: |
|||
return new TenantId(uuid); |
|||
case CUSTOMER: |
|||
return new CustomerId(uuid); |
|||
case USER: |
|||
return new UserId(uuid); |
|||
case RULE: |
|||
return new RuleId(uuid); |
|||
case PLUGIN: |
|||
return new PluginId(uuid); |
|||
case DASHBOARD: |
|||
return new DashboardId(uuid); |
|||
case DEVICE: |
|||
return new DeviceId(uuid); |
|||
case ASSET: |
|||
return new AssetId(uuid); |
|||
} |
|||
throw new IllegalArgumentException("EntityType " + type + " is not supported!"); |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.id; |
|||
|
|||
import com.fasterxml.jackson.core.JsonGenerator; |
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import com.fasterxml.jackson.databind.JsonSerializer; |
|||
import com.fasterxml.jackson.databind.SerializerProvider; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* Created by ashvayka on 11.05.17. |
|||
*/ |
|||
public class EntityIdSerializer extends JsonSerializer<EntityId> { |
|||
|
|||
@Override |
|||
public void serialize(EntityId value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException { |
|||
gen.writeStartObject(); |
|||
gen.writeStringField("entityType", value.getEntityType().name()); |
|||
gen.writeStringField("id", value.getId().toString()); |
|||
gen.writeEndObject(); |
|||
} |
|||
} |
|||
@ -0,0 +1,103 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.relation; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
|
|||
import java.util.Objects; |
|||
|
|||
public class EntityRelation { |
|||
|
|||
private static final long serialVersionUID = 2807343040519543363L; |
|||
|
|||
public static final String CONTAINS_TYPE = "Contains"; |
|||
public static final String MANAGES_TYPE = "Manages"; |
|||
|
|||
private EntityId from; |
|||
private EntityId to; |
|||
private String type; |
|||
private JsonNode additionalInfo; |
|||
|
|||
public EntityRelation() { |
|||
super(); |
|||
} |
|||
|
|||
public EntityRelation(EntityId from, EntityId to, String type) { |
|||
this(from, to, type, null); |
|||
} |
|||
|
|||
public EntityRelation(EntityId from, EntityId to, String type, JsonNode additionalInfo) { |
|||
this.from = from; |
|||
this.to = to; |
|||
this.type = type; |
|||
this.additionalInfo = additionalInfo; |
|||
} |
|||
|
|||
public EntityRelation(EntityRelation device) { |
|||
this.from = device.getFrom(); |
|||
this.to = device.getTo(); |
|||
this.type = device.getType(); |
|||
this.additionalInfo = device.getAdditionalInfo(); |
|||
} |
|||
|
|||
public EntityId getFrom() { |
|||
return from; |
|||
} |
|||
|
|||
public void setFrom(EntityId from) { |
|||
this.from = from; |
|||
} |
|||
|
|||
public EntityId getTo() { |
|||
return to; |
|||
} |
|||
|
|||
public void setTo(EntityId to) { |
|||
this.to = to; |
|||
} |
|||
|
|||
public String getType() { |
|||
return type; |
|||
} |
|||
|
|||
public void setType(String type) { |
|||
this.type = type; |
|||
} |
|||
|
|||
public JsonNode getAdditionalInfo() { |
|||
return additionalInfo; |
|||
} |
|||
|
|||
public void setAdditionalInfo(JsonNode additionalInfo) { |
|||
this.additionalInfo = additionalInfo; |
|||
} |
|||
|
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) return true; |
|||
if (o == null || getClass() != o.getClass()) return false; |
|||
EntityRelation relation = (EntityRelation) o; |
|||
return Objects.equals(from, relation.from) && |
|||
Objects.equals(to, relation.to) && |
|||
Objects.equals(type, relation.type); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(from, to, type); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.alarm; |
|||
|
|||
/** |
|||
* Created by ashvayka on 11.05.17. |
|||
*/ |
|||
public interface AlarmDao { |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.alarm; |
|||
|
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import org.thingsboard.server.common.data.alarm.Alarm; |
|||
import org.thingsboard.server.common.data.alarm.AlarmId; |
|||
import org.thingsboard.server.common.data.alarm.AlarmQuery; |
|||
import org.thingsboard.server.common.data.page.TimePageData; |
|||
|
|||
import java.util.Optional; |
|||
|
|||
/** |
|||
* Created by ashvayka on 11.05.17. |
|||
*/ |
|||
public interface AlarmService { |
|||
|
|||
Optional<Alarm> saveIfNotExists(Alarm alarm); |
|||
|
|||
ListenableFuture<Boolean> updateAlarm(Alarm alarm); |
|||
|
|||
ListenableFuture<Boolean> ackAlarm(Alarm alarm); |
|||
|
|||
ListenableFuture<Boolean> clearAlarm(AlarmId alarmId); |
|||
|
|||
ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query); |
|||
|
|||
} |
|||
@ -0,0 +1,90 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.asset; |
|||
|
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.Dao; |
|||
import org.thingsboard.server.dao.model.AssetEntity; |
|||
import org.thingsboard.server.dao.model.DeviceEntity; |
|||
|
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
import java.util.UUID; |
|||
|
|||
/** |
|||
* The Interface AssetDao. |
|||
* |
|||
*/ |
|||
public interface AssetDao extends Dao<AssetEntity> { |
|||
|
|||
/** |
|||
* Save or update asset object |
|||
* |
|||
* @param asset the asset object |
|||
* @return saved asset object |
|||
*/ |
|||
AssetEntity save(Asset asset); |
|||
|
|||
/** |
|||
* Find assets by tenantId and page link. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param pageLink the page link |
|||
* @return the list of asset objects |
|||
*/ |
|||
List<AssetEntity> findAssetsByTenantId(UUID tenantId, TextPageLink pageLink); |
|||
|
|||
/** |
|||
* Find assets by tenantId and assets Ids. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param assetIds the asset Ids |
|||
* @return the list of asset objects |
|||
*/ |
|||
ListenableFuture<List<AssetEntity>> findAssetsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetIds); |
|||
|
|||
/** |
|||
* Find assets by tenantId, customerId and page link. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param customerId the customerId |
|||
* @param pageLink the page link |
|||
* @return the list of asset objects |
|||
*/ |
|||
List<AssetEntity> findAssetsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); |
|||
|
|||
/** |
|||
* Find assets by tenantId, customerId and assets Ids. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param customerId the customerId |
|||
* @param assetIds the asset Ids |
|||
* @return the list of asset objects |
|||
*/ |
|||
ListenableFuture<List<AssetEntity>> findAssetsByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> assetIds); |
|||
|
|||
/** |
|||
* Find assets by tenantId and asset name. |
|||
* |
|||
* @param tenantId the tenantId |
|||
* @param name the asset name |
|||
* @return the optional asset object |
|||
*/ |
|||
Optional<AssetEntity> findAssetsByTenantIdAndName(UUID tenantId, String name); |
|||
} |
|||
@ -0,0 +1,104 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.asset; |
|||
|
|||
import com.datastax.driver.core.querybuilder.Select; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.dao.AbstractSearchTextDao; |
|||
import org.thingsboard.server.dao.model.AssetEntity; |
|||
|
|||
import java.util.*; |
|||
|
|||
import static com.datastax.driver.core.querybuilder.QueryBuilder.*; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.*; |
|||
|
|||
@Component |
|||
@Slf4j |
|||
public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements AssetDao { |
|||
|
|||
@Override |
|||
protected Class<AssetEntity> getColumnFamilyClass() { |
|||
return AssetEntity.class; |
|||
} |
|||
|
|||
@Override |
|||
protected String getColumnFamilyName() { |
|||
return ASSET_COLUMN_FAMILY_NAME; |
|||
} |
|||
|
|||
@Override |
|||
public AssetEntity save(Asset asset) { |
|||
log.debug("Save asset [{}] ", asset); |
|||
return save(new AssetEntity(asset)); |
|||
} |
|||
|
|||
@Override |
|||
public List<AssetEntity> findAssetsByTenantId(UUID tenantId, TextPageLink pageLink) { |
|||
log.debug("Try to find assets by tenantId [{}] and pageLink [{}]", tenantId, pageLink); |
|||
List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, |
|||
Collections.singletonList(eq(ASSET_TENANT_ID_PROPERTY, tenantId)), pageLink); |
|||
|
|||
log.trace("Found assets [{}] by tenantId [{}] and pageLink [{}]", assetEntities, tenantId, pageLink); |
|||
return assetEntities; |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetIds) { |
|||
log.debug("Try to find assets by tenantId [{}] and asset Ids [{}]", tenantId, assetIds); |
|||
Select select = select().from(getColumnFamilyName()); |
|||
Select.Where query = select.where(); |
|||
query.and(eq(ASSET_TENANT_ID_PROPERTY, tenantId)); |
|||
query.and(in(ID_PROPERTY, assetIds)); |
|||
return findListByStatementAsync(query); |
|||
} |
|||
|
|||
@Override |
|||
public List<AssetEntity> findAssetsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { |
|||
log.debug("Try to find assets by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink); |
|||
List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, |
|||
Arrays.asList(eq(ASSET_CUSTOMER_ID_PROPERTY, customerId), |
|||
eq(ASSET_TENANT_ID_PROPERTY, tenantId)), |
|||
pageLink); |
|||
|
|||
log.trace("Found assets [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", assetEntities, tenantId, customerId, pageLink); |
|||
return assetEntities; |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> assetIds) { |
|||
log.debug("Try to find assets by tenantId [{}], customerId [{}] and asset Ids [{}]", tenantId, customerId, assetIds); |
|||
Select select = select().from(getColumnFamilyName()); |
|||
Select.Where query = select.where(); |
|||
query.and(eq(ASSET_TENANT_ID_PROPERTY, tenantId)); |
|||
query.and(eq(ASSET_CUSTOMER_ID_PROPERTY, customerId)); |
|||
query.and(in(ID_PROPERTY, assetIds)); |
|||
return findListByStatementAsync(query); |
|||
} |
|||
|
|||
@Override |
|||
public Optional<AssetEntity> findAssetsByTenantIdAndName(UUID tenantId, String assetName) { |
|||
Select select = select().from(ASSET_BY_TENANT_AND_NAME_VIEW_NAME); |
|||
Select.Where query = select.where(); |
|||
query.and(eq(ASSET_TENANT_ID_PROPERTY, tenantId)); |
|||
query.and(eq(ASSET_NAME_PROPERTY, assetName)); |
|||
return Optional.ofNullable(findOneByStatement(query)); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.asset; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.relation.EntityRelation; |
|||
import org.thingsboard.server.dao.relation.RelationsSearchParameters; |
|||
import org.thingsboard.server.dao.relation.EntityRelationsQuery; |
|||
import org.thingsboard.server.dao.relation.EntityTypeFilter; |
|||
|
|||
import javax.annotation.Nullable; |
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* Created by ashvayka on 03.05.17. |
|||
*/ |
|||
@Data |
|||
public class AssetSearchQuery { |
|||
|
|||
private RelationsSearchParameters parameters; |
|||
@Nullable |
|||
private String relationType; |
|||
@Nullable |
|||
private List<String> assetTypes; |
|||
|
|||
public EntityRelationsQuery toEntitySearchQuery() { |
|||
EntityRelationsQuery query = new EntityRelationsQuery(); |
|||
query.setParameters(parameters); |
|||
query.setFilters( |
|||
Collections.singletonList(new EntityTypeFilter(relationType == null ? EntityRelation.CONTAINS_TYPE : relationType, |
|||
Collections.singletonList(EntityType.ASSET)))); |
|||
return query; |
|||
} |
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.asset; |
|||
|
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
|
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
|
|||
public interface AssetService { |
|||
|
|||
Asset findAssetById(AssetId assetId); |
|||
|
|||
ListenableFuture<Asset> findAssetByIdAsync(AssetId assetId); |
|||
|
|||
Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name); |
|||
|
|||
Asset saveAsset(Asset device); |
|||
|
|||
Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId); |
|||
|
|||
Asset unassignAssetFromCustomer(AssetId assetId); |
|||
|
|||
void deleteAsset(AssetId assetId); |
|||
|
|||
TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink); |
|||
|
|||
ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds); |
|||
|
|||
void deleteAssetsByTenantId(TenantId tenantId); |
|||
|
|||
TextPageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); |
|||
|
|||
ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds); |
|||
|
|||
void unassignCustomerAssets(TenantId tenantId, CustomerId customerId); |
|||
|
|||
ListenableFuture<List<Asset>> findAssetsByQuery(AssetSearchQuery query); |
|||
|
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.asset; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import javax.annotation.Nullable; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* Created by ashvayka on 02.05.17. |
|||
*/ |
|||
@Data |
|||
public class AssetTypeFilter { |
|||
@Nullable |
|||
private String relationType; |
|||
@Nullable |
|||
private List<String> assetTypes; |
|||
} |
|||
@ -0,0 +1,292 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.asset; |
|||
|
|||
|
|||
import com.google.common.base.Function; |
|||
import com.google.common.util.concurrent.AsyncFunction; |
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.util.StringUtils; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.relation.EntityRelation; |
|||
import org.thingsboard.server.dao.customer.CustomerDao; |
|||
import org.thingsboard.server.dao.entity.BaseEntityService; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
import org.thingsboard.server.dao.model.AssetEntity; |
|||
import org.thingsboard.server.dao.model.CustomerEntity; |
|||
import org.thingsboard.server.dao.model.TenantEntity; |
|||
import org.thingsboard.server.dao.relation.EntityRelationsQuery; |
|||
import org.thingsboard.server.dao.relation.EntitySearchDirection; |
|||
import org.thingsboard.server.dao.service.DataValidator; |
|||
import org.thingsboard.server.dao.service.PaginatedRemover; |
|||
import org.thingsboard.server.dao.tenant.TenantDao; |
|||
|
|||
import javax.annotation.Nullable; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
import java.util.stream.Collectors; |
|||
|
|||
import static org.thingsboard.server.dao.DaoUtil.*; |
|||
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; |
|||
import static org.thingsboard.server.dao.service.Validator.*; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
public class BaseAssetService extends BaseEntityService implements AssetService { |
|||
|
|||
@Autowired |
|||
private AssetDao assetDao; |
|||
|
|||
@Autowired |
|||
private TenantDao tenantDao; |
|||
|
|||
@Autowired |
|||
private CustomerDao customerDao; |
|||
|
|||
@Override |
|||
public Asset findAssetById(AssetId assetId) { |
|||
log.trace("Executing findAssetById [{}]", assetId); |
|||
validateId(assetId, "Incorrect assetId " + assetId); |
|||
AssetEntity assetEntity = assetDao.findById(assetId.getId()); |
|||
return getData(assetEntity); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Asset> findAssetByIdAsync(AssetId assetId) { |
|||
log.trace("Executing findAssetById [{}]", assetId); |
|||
validateId(assetId, "Incorrect assetId " + assetId); |
|||
ListenableFuture<AssetEntity> assetEntity = assetDao.findByIdAsync(assetId.getId()); |
|||
return Futures.transform(assetEntity, (Function<? super AssetEntity, ? extends Asset>) input -> getData(input)); |
|||
} |
|||
|
|||
@Override |
|||
public Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name) { |
|||
log.trace("Executing findAssetByTenantIdAndName [{}][{}]", tenantId, name); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
Optional<AssetEntity> assetEntityOpt = assetDao.findAssetsByTenantIdAndName(tenantId.getId(), name); |
|||
if (assetEntityOpt.isPresent()) { |
|||
return Optional.of(getData(assetEntityOpt.get())); |
|||
} else { |
|||
return Optional.empty(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Asset saveAsset(Asset asset) { |
|||
log.trace("Executing saveAsset [{}]", asset); |
|||
assetValidator.validate(asset); |
|||
return getData(assetDao.save(asset)); |
|||
} |
|||
|
|||
@Override |
|||
public Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId) { |
|||
Asset asset = findAssetById(assetId); |
|||
asset.setCustomerId(customerId); |
|||
return saveAsset(asset); |
|||
} |
|||
|
|||
@Override |
|||
public Asset unassignAssetFromCustomer(AssetId assetId) { |
|||
Asset asset = findAssetById(assetId); |
|||
asset.setCustomerId(null); |
|||
return saveAsset(asset); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteAsset(AssetId assetId) { |
|||
log.trace("Executing deleteAsset [{}]", assetId); |
|||
validateId(assetId, "Incorrect assetId " + assetId); |
|||
deleteEntityRelations(assetId); |
|||
assetDao.removeById(assetId.getId()); |
|||
} |
|||
|
|||
@Override |
|||
public TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink) { |
|||
log.trace("Executing findAssetsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
validatePageLink(pageLink, "Incorrect page link " + pageLink); |
|||
List<AssetEntity> assetEntities = assetDao.findAssetsByTenantId(tenantId.getId(), pageLink); |
|||
List<Asset> assets = convertDataList(assetEntities); |
|||
return new TextPageData<Asset>(assets, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds) { |
|||
log.trace("Executing findAssetsByTenantIdAndIdsAsync, tenantId [{}], assetIds [{}]", tenantId, assetIds); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
validateIds(assetIds, "Incorrect assetIds " + assetIds); |
|||
ListenableFuture<List<AssetEntity>> assetEntities = assetDao.findAssetsByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(assetIds)); |
|||
return Futures.transform(assetEntities, (Function<List<AssetEntity>, List<Asset>>) input -> convertDataList(input)); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteAssetsByTenantId(TenantId tenantId) { |
|||
log.trace("Executing deleteAssetsByTenantId, tenantId [{}]", tenantId); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
tenantAssetsRemover.removeEntitites(tenantId); |
|||
} |
|||
|
|||
@Override |
|||
public TextPageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink) { |
|||
log.trace("Executing findAssetsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
validateId(customerId, "Incorrect customerId " + customerId); |
|||
validatePageLink(pageLink, "Incorrect page link " + pageLink); |
|||
List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); |
|||
List<Asset> assets = convertDataList(assetEntities); |
|||
return new TextPageData<Asset>(assets, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds) { |
|||
log.trace("Executing findAssetsByTenantIdCustomerIdAndIdsAsync, tenantId [{}], customerId [{}], assetIds [{}]", tenantId, customerId, assetIds); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
validateId(customerId, "Incorrect customerId " + customerId); |
|||
validateIds(assetIds, "Incorrect assetIds " + assetIds); |
|||
ListenableFuture<List<AssetEntity>> assetEntities = assetDao.findAssetsByTenantIdCustomerIdAndIdsAsync(tenantId.getId(), |
|||
customerId.getId(), toUUIDs(assetIds)); |
|||
return Futures.transform(assetEntities, (Function<List<AssetEntity>, List<Asset>>) input -> convertDataList(input)); |
|||
} |
|||
|
|||
@Override |
|||
public void unassignCustomerAssets(TenantId tenantId, CustomerId customerId) { |
|||
log.trace("Executing unassignCustomerAssets, tenantId [{}], customerId [{}]", tenantId, customerId); |
|||
validateId(tenantId, "Incorrect tenantId " + tenantId); |
|||
validateId(customerId, "Incorrect customerId " + customerId); |
|||
new CustomerAssetsUnassigner(tenantId).removeEntitites(customerId); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<Asset>> findAssetsByQuery(AssetSearchQuery query) { |
|||
ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(query.toEntitySearchQuery()); |
|||
ListenableFuture<List<Asset>> assets = Futures.transform(relations, (AsyncFunction<List<EntityRelation>, List<Asset>>) relations1 -> { |
|||
EntitySearchDirection direction = query.toEntitySearchQuery().getParameters().getDirection(); |
|||
List<ListenableFuture<Asset>> futures = new ArrayList<>(); |
|||
for (EntityRelation relation : relations1) { |
|||
EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom(); |
|||
if (entityId.getEntityType() == EntityType.ASSET) { |
|||
futures.add(findAssetByIdAsync(new AssetId(entityId.getId()))); |
|||
} |
|||
} |
|||
return Futures.successfulAsList(futures); |
|||
}); |
|||
|
|||
assets = Futures.transform(assets, new Function<List<Asset>, List<Asset>>() { |
|||
@Nullable |
|||
@Override |
|||
public List<Asset> apply(@Nullable List<Asset> assetList) { |
|||
return assetList.stream().filter(asset -> query.getAssetTypes().contains(asset.getType())).collect(Collectors.toList()); |
|||
} |
|||
}); |
|||
|
|||
return assets; |
|||
} |
|||
|
|||
private DataValidator<Asset> assetValidator = |
|||
new DataValidator<Asset>() { |
|||
|
|||
@Override |
|||
protected void validateCreate(Asset asset) { |
|||
assetDao.findAssetsByTenantIdAndName(asset.getTenantId().getId(), asset.getName()).ifPresent( |
|||
d -> { |
|||
throw new DataValidationException("Asset with such name already exists!"); |
|||
} |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
protected void validateUpdate(Asset asset) { |
|||
assetDao.findAssetsByTenantIdAndName(asset.getTenantId().getId(), asset.getName()).ifPresent( |
|||
d -> { |
|||
if (!d.getId().equals(asset.getUuidId())) { |
|||
throw new DataValidationException("Asset with such name already exists!"); |
|||
} |
|||
} |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
protected void validateDataImpl(Asset asset) { |
|||
if (StringUtils.isEmpty(asset.getName())) { |
|||
throw new DataValidationException("Asset name should be specified!"); |
|||
} |
|||
if (asset.getTenantId() == null) { |
|||
throw new DataValidationException("Asset should be assigned to tenant!"); |
|||
} else { |
|||
TenantEntity tenant = tenantDao.findById(asset.getTenantId().getId()); |
|||
if (tenant == null) { |
|||
throw new DataValidationException("Asset is referencing to non-existent tenant!"); |
|||
} |
|||
} |
|||
if (asset.getCustomerId() == null) { |
|||
asset.setCustomerId(new CustomerId(NULL_UUID)); |
|||
} else if (!asset.getCustomerId().getId().equals(NULL_UUID)) { |
|||
CustomerEntity customer = customerDao.findById(asset.getCustomerId().getId()); |
|||
if (customer == null) { |
|||
throw new DataValidationException("Can't assign asset to non-existent customer!"); |
|||
} |
|||
if (!customer.getTenantId().equals(asset.getTenantId().getId())) { |
|||
throw new DataValidationException("Can't assign asset to customer from different tenant!"); |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
private PaginatedRemover<TenantId, AssetEntity> tenantAssetsRemover = |
|||
new PaginatedRemover<TenantId, AssetEntity>() { |
|||
|
|||
@Override |
|||
protected List<AssetEntity> findEntities(TenantId id, TextPageLink pageLink) { |
|||
return assetDao.findAssetsByTenantId(id.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
protected void removeEntity(AssetEntity entity) { |
|||
deleteAsset(new AssetId(entity.getId())); |
|||
} |
|||
}; |
|||
|
|||
class CustomerAssetsUnassigner extends PaginatedRemover<CustomerId, AssetEntity> { |
|||
|
|||
private TenantId tenantId; |
|||
|
|||
CustomerAssetsUnassigner(TenantId tenantId) { |
|||
this.tenantId = tenantId; |
|||
} |
|||
|
|||
@Override |
|||
protected List<AssetEntity> findEntities(CustomerId id, TextPageLink pageLink) { |
|||
return assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
protected void removeEntity(AssetEntity entity) { |
|||
unassignAssetFromCustomer(new AssetId(entity.getId())); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.device; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.relation.EntityRelation; |
|||
import org.thingsboard.server.dao.relation.RelationsSearchParameters; |
|||
import org.thingsboard.server.dao.relation.EntityRelationsQuery; |
|||
import org.thingsboard.server.dao.relation.EntityTypeFilter; |
|||
|
|||
import javax.annotation.Nullable; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public class DeviceSearchQuery { |
|||
|
|||
private RelationsSearchParameters parameters; |
|||
@Nullable |
|||
private String relationType; |
|||
@Nullable |
|||
private List<String> deviceTypes; |
|||
|
|||
public EntityRelationsQuery toEntitySearchQuery() { |
|||
EntityRelationsQuery query = new EntityRelationsQuery(); |
|||
query.setParameters(parameters); |
|||
query.setFilters( |
|||
Collections.singletonList(new EntityTypeFilter(relationType == null ? EntityRelation.CONTAINS_TYPE : relationType, |
|||
Collections.singletonList(EntityType.DEVICE)))); |
|||
return query; |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.entity; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.dao.relation.RelationService; |
|||
|
|||
/** |
|||
* Created by ashvayka on 04.05.17. |
|||
*/ |
|||
@Slf4j |
|||
public class BaseEntityService { |
|||
|
|||
@Autowired |
|||
protected RelationService relationService; |
|||
|
|||
protected void deleteEntityRelations(EntityId entityId) { |
|||
log.trace("Executing deleteEntityRelations [{}]", entityId); |
|||
relationService.deleteEntityRelations(entityId); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,235 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.model; |
|||
|
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import com.datastax.driver.mapping.annotations.Column; |
|||
import com.datastax.driver.mapping.annotations.PartitionKey; |
|||
import com.datastax.driver.mapping.annotations.Table; |
|||
import com.datastax.driver.mapping.annotations.Transient; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.dao.model.type.JsonCodec; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.dao.model.ModelConstants.*; |
|||
|
|||
@Table(name = ASSET_COLUMN_FAMILY_NAME) |
|||
public final class AssetEntity implements SearchTextEntity<Asset> { |
|||
|
|||
@Transient |
|||
private static final long serialVersionUID = -1265181166886910152L; |
|||
|
|||
@PartitionKey(value = 0) |
|||
@Column(name = ID_PROPERTY) |
|||
private UUID id; |
|||
|
|||
@PartitionKey(value = 1) |
|||
@Column(name = ASSET_TENANT_ID_PROPERTY) |
|||
private UUID tenantId; |
|||
|
|||
@PartitionKey(value = 2) |
|||
@Column(name = ASSET_CUSTOMER_ID_PROPERTY) |
|||
private UUID customerId; |
|||
|
|||
@Column(name = ASSET_NAME_PROPERTY) |
|||
private String name; |
|||
|
|||
@Column(name = ASSET_TYPE_PROPERTY) |
|||
private String type; |
|||
|
|||
@Column(name = SEARCH_TEXT_PROPERTY) |
|||
private String searchText; |
|||
|
|||
@Column(name = ASSET_ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class) |
|||
private JsonNode additionalInfo; |
|||
|
|||
public AssetEntity() { |
|||
super(); |
|||
} |
|||
|
|||
public AssetEntity(Asset asset) { |
|||
if (asset.getId() != null) { |
|||
this.id = asset.getId().getId(); |
|||
} |
|||
if (asset.getTenantId() != null) { |
|||
this.tenantId = asset.getTenantId().getId(); |
|||
} |
|||
if (asset.getCustomerId() != null) { |
|||
this.customerId = asset.getCustomerId().getId(); |
|||
} |
|||
this.name = asset.getName(); |
|||
this.type = asset.getType(); |
|||
this.additionalInfo = asset.getAdditionalInfo(); |
|||
} |
|||
|
|||
public UUID getId() { |
|||
return id; |
|||
} |
|||
|
|||
public void setId(UUID id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
public UUID getTenantId() { |
|||
return tenantId; |
|||
} |
|||
|
|||
public void setTenantId(UUID tenantId) { |
|||
this.tenantId = tenantId; |
|||
} |
|||
|
|||
public UUID getCustomerId() { |
|||
return customerId; |
|||
} |
|||
|
|||
public void setCustomerId(UUID customerId) { |
|||
this.customerId = customerId; |
|||
} |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
public void setName(String name) { |
|||
this.name = name; |
|||
} |
|||
|
|||
public String getType() { |
|||
return type; |
|||
} |
|||
|
|||
public void setType(String type) { |
|||
this.type = type; |
|||
} |
|||
|
|||
public JsonNode getAdditionalInfo() { |
|||
return additionalInfo; |
|||
} |
|||
|
|||
public void setAdditionalInfo(JsonNode additionalInfo) { |
|||
this.additionalInfo = additionalInfo; |
|||
} |
|||
|
|||
@Override |
|||
public String getSearchTextSource() { |
|||
return name; |
|||
} |
|||
|
|||
@Override |
|||
public void setSearchText(String searchText) { |
|||
this.searchText = searchText; |
|||
} |
|||
|
|||
public String getSearchText() { |
|||
return searchText; |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
final int prime = 31; |
|||
int result = 1; |
|||
result = prime * result + ((additionalInfo == null) ? 0 : additionalInfo.hashCode()); |
|||
result = prime * result + ((customerId == null) ? 0 : customerId.hashCode()); |
|||
result = prime * result + ((id == null) ? 0 : id.hashCode()); |
|||
result = prime * result + ((name == null) ? 0 : name.hashCode()); |
|||
result = prime * result + ((type == null) ? 0 : type.hashCode()); |
|||
result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode()); |
|||
return result; |
|||
} |
|||
|
|||
@Override |
|||
public boolean equals(Object obj) { |
|||
if (this == obj) |
|||
return true; |
|||
if (obj == null) |
|||
return false; |
|||
if (getClass() != obj.getClass()) |
|||
return false; |
|||
AssetEntity other = (AssetEntity) obj; |
|||
if (additionalInfo == null) { |
|||
if (other.additionalInfo != null) |
|||
return false; |
|||
} else if (!additionalInfo.equals(other.additionalInfo)) |
|||
return false; |
|||
if (customerId == null) { |
|||
if (other.customerId != null) |
|||
return false; |
|||
} else if (!customerId.equals(other.customerId)) |
|||
return false; |
|||
if (id == null) { |
|||
if (other.id != null) |
|||
return false; |
|||
} else if (!id.equals(other.id)) |
|||
return false; |
|||
if (name == null) { |
|||
if (other.name != null) |
|||
return false; |
|||
} else if (!name.equals(other.name)) |
|||
return false; |
|||
if (type == null) { |
|||
if (other.type != null) |
|||
return false; |
|||
} else if (!type.equals(other.type)) |
|||
return false; |
|||
if (tenantId == null) { |
|||
if (other.tenantId != null) |
|||
return false; |
|||
} else if (!tenantId.equals(other.tenantId)) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
StringBuilder builder = new StringBuilder(); |
|||
builder.append("AssetEntity [id="); |
|||
builder.append(id); |
|||
builder.append(", tenantId="); |
|||
builder.append(tenantId); |
|||
builder.append(", customerId="); |
|||
builder.append(customerId); |
|||
builder.append(", name="); |
|||
builder.append(name); |
|||
builder.append(", type="); |
|||
builder.append(type); |
|||
builder.append(", additionalInfo="); |
|||
builder.append(additionalInfo); |
|||
builder.append("]"); |
|||
return builder.toString(); |
|||
} |
|||
|
|||
@Override |
|||
public Asset toData() { |
|||
Asset asset = new Asset(new AssetId(id)); |
|||
asset.setCreatedTime(UUIDs.unixTimestamp(id)); |
|||
if (tenantId != null) { |
|||
asset.setTenantId(new TenantId(tenantId)); |
|||
} |
|||
if (customerId != null) { |
|||
asset.setCustomerId(new CustomerId(customerId)); |
|||
} |
|||
asset.setName(name); |
|||
asset.setType(type); |
|||
asset.setAdditionalInfo(additionalInfo); |
|||
return asset; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,279 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.relation; |
|||
|
|||
import com.datastax.driver.core.*; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.google.common.base.Function; |
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|||
import org.thingsboard.server.common.data.relation.EntityRelation; |
|||
import org.thingsboard.server.dao.AbstractAsyncDao; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
|
|||
import javax.annotation.Nullable; |
|||
import javax.annotation.PostConstruct; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* Created by ashvayka on 25.04.17. |
|||
*/ |
|||
@Component |
|||
@Slf4j |
|||
public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { |
|||
|
|||
private static final String SELECT_COLUMNS = "SELECT " + |
|||
ModelConstants.RELATION_FROM_ID_PROPERTY + "," + |
|||
ModelConstants.RELATION_FROM_TYPE_PROPERTY + "," + |
|||
ModelConstants.RELATION_TO_ID_PROPERTY + "," + |
|||
ModelConstants.RELATION_TO_TYPE_PROPERTY + "," + |
|||
ModelConstants.RELATION_TYPE_PROPERTY + "," + |
|||
ModelConstants.ADDITIONAL_INFO_PROPERTY; |
|||
public static final String FROM = " FROM "; |
|||
public static final String WHERE = " WHERE "; |
|||
public static final String AND = " AND "; |
|||
|
|||
private PreparedStatement saveStmt; |
|||
private PreparedStatement findAllByFromStmt; |
|||
private PreparedStatement findAllByFromAndTypeStmt; |
|||
private PreparedStatement findAllByToStmt; |
|||
private PreparedStatement findAllByToAndTypeStmt; |
|||
private PreparedStatement checkRelationStmt; |
|||
private PreparedStatement deleteStmt; |
|||
private PreparedStatement deleteAllByEntityStmt; |
|||
|
|||
@PostConstruct |
|||
public void init() { |
|||
super.startExecutor(); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<EntityRelation>> findAllByFrom(EntityId from) { |
|||
BoundStatement stmt = getFindAllByFromStmt().bind().setUUID(0, from.getId()).setString(1, from.getEntityType().name()); |
|||
return executeAsyncRead(from, stmt); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<EntityRelation>> findAllByFromAndType(EntityId from, String relationType) { |
|||
BoundStatement stmt = getFindAllByFromAndTypeStmt().bind() |
|||
.setUUID(0, from.getId()) |
|||
.setString(1, from.getEntityType().name()) |
|||
.setString(2, relationType); |
|||
return executeAsyncRead(from, stmt); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<EntityRelation>> findAllByTo(EntityId to) { |
|||
BoundStatement stmt = getFindAllByToStmt().bind().setUUID(0, to.getId()).setString(1, to.getEntityType().name()); |
|||
return executeAsyncRead(to, stmt); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<EntityRelation>> findAllByToAndType(EntityId to, String relationType) { |
|||
BoundStatement stmt = getFindAllByToAndTypeStmt().bind() |
|||
.setUUID(0, to.getId()) |
|||
.setString(1, to.getEntityType().name()) |
|||
.setString(2, relationType); |
|||
return executeAsyncRead(to, stmt); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType) { |
|||
BoundStatement stmt = getCheckRelationStmt().bind() |
|||
.setUUID(0, from.getId()) |
|||
.setString(1, from.getEntityType().name()) |
|||
.setUUID(2, to.getId()) |
|||
.setString(3, to.getEntityType().name()) |
|||
.setString(4, relationType); |
|||
return getFuture(executeAsyncRead(stmt), rs -> rs != null ? rs.one() != null : false); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Boolean> saveRelation(EntityRelation relation) { |
|||
BoundStatement stmt = getSaveStmt().bind() |
|||
.setUUID(0, relation.getFrom().getId()) |
|||
.setString(1, relation.getFrom().getEntityType().name()) |
|||
.setUUID(2, relation.getTo().getId()) |
|||
.setString(3, relation.getTo().getEntityType().name()) |
|||
.setString(4, relation.getType()) |
|||
.set(5, relation.getAdditionalInfo(), JsonNode.class); |
|||
ResultSetFuture future = executeAsyncWrite(stmt); |
|||
return getBooleanListenableFuture(future); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Boolean> deleteRelation(EntityRelation relation) { |
|||
return deleteRelation(relation.getFrom(), relation.getTo(), relation.getType()); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Boolean> deleteRelation(EntityId from, EntityId to, String relationType) { |
|||
BoundStatement stmt = getDeleteStmt().bind() |
|||
.setUUID(0, from.getId()) |
|||
.setString(1, from.getEntityType().name()) |
|||
.setUUID(2, to.getId()) |
|||
.setString(3, to.getEntityType().name()) |
|||
.setString(4, relationType); |
|||
ResultSetFuture future = executeAsyncWrite(stmt); |
|||
return getBooleanListenableFuture(future); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Boolean> deleteOutboundRelations(EntityId entity) { |
|||
BoundStatement stmt = getDeleteAllByEntityStmt().bind() |
|||
.setUUID(0, entity.getId()) |
|||
.setString(1, entity.getEntityType().name()); |
|||
ResultSetFuture future = executeAsyncWrite(stmt); |
|||
return getBooleanListenableFuture(future); |
|||
} |
|||
|
|||
private PreparedStatement getSaveStmt() { |
|||
if (saveStmt == null) { |
|||
saveStmt = getSession().prepare("INSERT INTO " + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " + |
|||
"(" + ModelConstants.RELATION_FROM_ID_PROPERTY + |
|||
"," + ModelConstants.RELATION_FROM_TYPE_PROPERTY + |
|||
"," + ModelConstants.RELATION_TO_ID_PROPERTY + |
|||
"," + ModelConstants.RELATION_TO_TYPE_PROPERTY + |
|||
"," + ModelConstants.RELATION_TYPE_PROPERTY + |
|||
"," + ModelConstants.ADDITIONAL_INFO_PROPERTY + ")" + |
|||
" VALUES(?, ?, ?, ?, ?, ?)"); |
|||
} |
|||
return saveStmt; |
|||
} |
|||
|
|||
private PreparedStatement getDeleteStmt() { |
|||
if (deleteStmt == null) { |
|||
deleteStmt = getSession().prepare("DELETE FROM " + ModelConstants.RELATION_COLUMN_FAMILY_NAME + |
|||
WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ?" + |
|||
AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ?" + |
|||
AND + ModelConstants.RELATION_TO_ID_PROPERTY + " = ?" + |
|||
AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ?" + |
|||
AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ?"); |
|||
} |
|||
return deleteStmt; |
|||
} |
|||
|
|||
private PreparedStatement getDeleteAllByEntityStmt() { |
|||
if (deleteAllByEntityStmt == null) { |
|||
deleteAllByEntityStmt = getSession().prepare("DELETE FROM " + ModelConstants.RELATION_COLUMN_FAMILY_NAME + |
|||
WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ?" + |
|||
AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ?"); |
|||
} |
|||
return deleteAllByEntityStmt; |
|||
} |
|||
|
|||
private PreparedStatement getFindAllByFromStmt() { |
|||
if (findAllByFromStmt == null) { |
|||
findAllByFromStmt = getSession().prepare(SELECT_COLUMNS + " " + |
|||
FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " + |
|||
WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ? " + |
|||
AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? "); |
|||
} |
|||
return findAllByFromStmt; |
|||
} |
|||
|
|||
private PreparedStatement getFindAllByFromAndTypeStmt() { |
|||
if (findAllByFromAndTypeStmt == null) { |
|||
findAllByFromAndTypeStmt = getSession().prepare(SELECT_COLUMNS + " " + |
|||
FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " + |
|||
WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ? " + |
|||
AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? " + |
|||
AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? "); |
|||
} |
|||
return findAllByFromAndTypeStmt; |
|||
} |
|||
|
|||
private PreparedStatement getFindAllByToStmt() { |
|||
if (findAllByToStmt == null) { |
|||
findAllByToStmt = getSession().prepare(SELECT_COLUMNS + " " + |
|||
FROM + ModelConstants.RELATION_REVERSE_VIEW_NAME + " " + |
|||
WHERE + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " + |
|||
AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? "); |
|||
} |
|||
return findAllByToStmt; |
|||
} |
|||
|
|||
private PreparedStatement getFindAllByToAndTypeStmt() { |
|||
if (findAllByToAndTypeStmt == null) { |
|||
findAllByToAndTypeStmt = getSession().prepare(SELECT_COLUMNS + " " + |
|||
FROM + ModelConstants.RELATION_REVERSE_VIEW_NAME + " " + |
|||
WHERE + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " + |
|||
AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? " + |
|||
AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? "); |
|||
} |
|||
return findAllByToAndTypeStmt; |
|||
} |
|||
|
|||
private PreparedStatement getCheckRelationStmt() { |
|||
if (checkRelationStmt == null) { |
|||
checkRelationStmt = getSession().prepare(SELECT_COLUMNS + " " + |
|||
FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " + |
|||
WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ? " + |
|||
AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? " + |
|||
AND + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " + |
|||
AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? " + |
|||
AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? "); |
|||
} |
|||
return checkRelationStmt; |
|||
} |
|||
|
|||
private EntityRelation getEntityRelation(Row row) { |
|||
EntityRelation relation = new EntityRelation(); |
|||
relation.setType(row.getString(ModelConstants.RELATION_TYPE_PROPERTY)); |
|||
relation.setAdditionalInfo(row.get(ModelConstants.ADDITIONAL_INFO_PROPERTY, JsonNode.class)); |
|||
relation.setFrom(toEntity(row, ModelConstants.RELATION_FROM_ID_PROPERTY, ModelConstants.RELATION_FROM_TYPE_PROPERTY)); |
|||
relation.setTo(toEntity(row, ModelConstants.RELATION_TO_ID_PROPERTY, ModelConstants.RELATION_TO_TYPE_PROPERTY)); |
|||
return relation; |
|||
} |
|||
|
|||
private EntityId toEntity(Row row, String uuidColumn, String typeColumn) { |
|||
return EntityIdFactory.getByTypeAndUuid(row.getString(typeColumn), row.getUUID(uuidColumn)); |
|||
} |
|||
|
|||
private ListenableFuture<List<EntityRelation>> executeAsyncRead(EntityId from, BoundStatement stmt) { |
|||
log.debug("Generated query [{}] for entity {}", stmt, from); |
|||
return getFuture(executeAsyncRead(stmt), rs -> { |
|||
List<Row> rows = rs.all(); |
|||
List<EntityRelation> entries = new ArrayList<>(rows.size()); |
|||
if (!rows.isEmpty()) { |
|||
rows.forEach(row -> { |
|||
entries.add(getEntityRelation(row)); |
|||
}); |
|||
} |
|||
return entries; |
|||
}); |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> getBooleanListenableFuture(ResultSetFuture rsFuture) { |
|||
return getFuture(rsFuture, rs -> rs != null ? rs.wasApplied() : false); |
|||
} |
|||
|
|||
private <T> ListenableFuture<T> getFuture(ResultSetFuture future, java.util.function.Function<ResultSet, T> transformer) { |
|||
return Futures.transform(future, new Function<ResultSet, T>() { |
|||
@Nullable |
|||
@Override |
|||
public T apply(@Nullable ResultSet input) { |
|||
return transformer.apply(input); |
|||
} |
|||
}, readResultsProcessingExecutor); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,257 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.relation; |
|||
|
|||
import com.google.common.base.Function; |
|||
import com.google.common.util.concurrent.AsyncFunction; |
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.util.StringUtils; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.relation.EntityRelation; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
|
|||
import javax.annotation.Nullable; |
|||
import java.util.*; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
/** |
|||
* Created by ashvayka on 28.04.17. |
|||
*/ |
|||
@Service |
|||
@Slf4j |
|||
public class BaseRelationService implements RelationService { |
|||
|
|||
@Autowired |
|||
private RelationDao relationDao; |
|||
|
|||
@Override |
|||
public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType) { |
|||
log.trace("Executing checkRelation [{}][{}][{}]", from, to, relationType); |
|||
validate(from, to, relationType); |
|||
return relationDao.checkRelation(from, to, relationType); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Boolean> saveRelation(EntityRelation relation) { |
|||
log.trace("Executing saveRelation [{}]", relation); |
|||
validate(relation); |
|||
return relationDao.saveRelation(relation); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Boolean> deleteRelation(EntityRelation relation) { |
|||
log.trace("Executing deleteRelation [{}]", relation); |
|||
validate(relation); |
|||
return relationDao.deleteRelation(relation); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Boolean> deleteRelation(EntityId from, EntityId to, String relationType) { |
|||
log.trace("Executing deleteRelation [{}][{}][{}]", from, to, relationType); |
|||
validate(from, to, relationType); |
|||
return relationDao.deleteRelation(from, to, relationType); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Boolean> deleteEntityRelations(EntityId entity) { |
|||
log.trace("Executing deleteEntityRelations [{}]", entity); |
|||
validate(entity); |
|||
ListenableFuture<List<EntityRelation>> inboundRelations = relationDao.findAllByTo(entity); |
|||
ListenableFuture<List<Boolean>> inboundDeletions = Futures.transform(inboundRelations, new AsyncFunction<List<EntityRelation>, List<Boolean>>() { |
|||
@Override |
|||
public ListenableFuture<List<Boolean>> apply(List<EntityRelation> relations) throws Exception { |
|||
List<ListenableFuture<Boolean>> results = new ArrayList<>(); |
|||
for (EntityRelation relation : relations) { |
|||
results.add(relationDao.deleteRelation(relation)); |
|||
} |
|||
return Futures.allAsList(results); |
|||
} |
|||
}); |
|||
|
|||
ListenableFuture<Boolean> inboundFuture = Futures.transform(inboundDeletions, getListToBooleanFunction()); |
|||
|
|||
ListenableFuture<Boolean> outboundFuture = relationDao.deleteOutboundRelations(entity); |
|||
|
|||
return Futures.transform(Futures.allAsList(Arrays.asList(inboundFuture, outboundFuture)), getListToBooleanFunction()); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<EntityRelation>> findByFrom(EntityId from) { |
|||
log.trace("Executing findByFrom [{}]", from); |
|||
validate(from); |
|||
return relationDao.findAllByFrom(from); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType) { |
|||
log.trace("Executing findByFromAndType [{}][{}]", from, relationType); |
|||
validate(from); |
|||
validateType(relationType); |
|||
return relationDao.findAllByFromAndType(from, relationType); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<EntityRelation>> findByTo(EntityId to) { |
|||
log.trace("Executing findByTo [{}]", to); |
|||
validate(to); |
|||
return relationDao.findAllByTo(to); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<EntityRelation>> findByToAndType(EntityId to, String relationType) { |
|||
log.trace("Executing findByToAndType [{}][{}]", to, relationType); |
|||
validate(to); |
|||
validateType(relationType); |
|||
return relationDao.findAllByToAndType(to, relationType); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<List<EntityRelation>> findByQuery(EntityRelationsQuery query) { |
|||
log.trace("Executing findByQuery [{}][{}]", query); |
|||
RelationsSearchParameters params = query.getParameters(); |
|||
final List<EntityTypeFilter> filters = query.getFilters(); |
|||
if (filters == null || filters.isEmpty()) { |
|||
log.warn("Failed to query relations. Filters are not set [{}]", query); |
|||
throw new RuntimeException("Filters are not set!"); |
|||
} |
|||
|
|||
int maxLvl = params.getMaxLevel() > 0 ? params.getMaxLevel() : Integer.MAX_VALUE; |
|||
|
|||
try { |
|||
ListenableFuture<Set<EntityRelation>> relationSet = findRelationsRecursively(params.getEntityId(), params.getDirection(), maxLvl, new ConcurrentHashMap<>()); |
|||
return Futures.transform(relationSet, (Function<Set<EntityRelation>, List<EntityRelation>>) input -> { |
|||
List<EntityRelation> relations = new ArrayList<>(); |
|||
for (EntityRelation relation : input) { |
|||
for (EntityTypeFilter filter : filters) { |
|||
if (match(filter, relation, params.getDirection())) { |
|||
relations.add(relation); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
return relations; |
|||
}); |
|||
} catch (Exception e) { |
|||
log.warn("Failed to query relations: [{}]", query, e); |
|||
throw new RuntimeException(e); |
|||
} |
|||
} |
|||
|
|||
protected void validate(EntityRelation relation) { |
|||
if (relation == null) { |
|||
throw new DataValidationException("Relation type should be specified!"); |
|||
} |
|||
validate(relation.getFrom(), relation.getTo(), relation.getType()); |
|||
} |
|||
|
|||
protected void validate(EntityId from, EntityId to, String type) { |
|||
validateType(type); |
|||
if (from == null) { |
|||
throw new DataValidationException("Relation should contain from entity!"); |
|||
} |
|||
if (to == null) { |
|||
throw new DataValidationException("Relation should contain to entity!"); |
|||
} |
|||
} |
|||
|
|||
private void validateType(String type) { |
|||
if (StringUtils.isEmpty(type)) { |
|||
throw new DataValidationException("Relation type should be specified!"); |
|||
} |
|||
} |
|||
|
|||
protected void validate(EntityId entity) { |
|||
if (entity == null) { |
|||
throw new DataValidationException("Entity should be specified!"); |
|||
} |
|||
} |
|||
|
|||
private Function<List<Boolean>, Boolean> getListToBooleanFunction() { |
|||
return new Function<List<Boolean>, Boolean>() { |
|||
@Nullable |
|||
@Override |
|||
public Boolean apply(@Nullable List<Boolean> results) { |
|||
for (Boolean result : results) { |
|||
if (result == null || !result) { |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
}; |
|||
} |
|||
|
|||
private boolean match(EntityTypeFilter filter, EntityRelation relation, EntitySearchDirection direction) { |
|||
if (StringUtils.isEmpty(filter.getRelationType()) || filter.getRelationType().equals(relation.getType())) { |
|||
if (filter.getEntityTypes() == null || filter.getEntityTypes().isEmpty()) { |
|||
return true; |
|||
} else { |
|||
EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom(); |
|||
return filter.getEntityTypes().contains(entityId.getEntityType()); |
|||
} |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
private ListenableFuture<Set<EntityRelation>> findRelationsRecursively(final EntityId rootId, final EntitySearchDirection direction, int lvl, final ConcurrentHashMap<EntityId, Boolean> uniqueMap) throws Exception { |
|||
if (lvl == 0) { |
|||
return Futures.immediateFuture(Collections.emptySet()); |
|||
} |
|||
lvl--; |
|||
//TODO: try to remove this blocking operation
|
|||
Set<EntityRelation> children = new HashSet<>(findRelations(rootId, direction).get()); |
|||
Set<EntityId> childrenIds = new HashSet<>(); |
|||
for (EntityRelation childRelation : children) { |
|||
log.info("Found Relation: {}", childRelation); |
|||
EntityId childId; |
|||
if (direction == EntitySearchDirection.FROM) { |
|||
childId = childRelation.getTo(); |
|||
} else { |
|||
childId = childRelation.getFrom(); |
|||
} |
|||
if (uniqueMap.putIfAbsent(childId, Boolean.TRUE) == null) { |
|||
log.info("Adding Relation: {}", childId); |
|||
if (childrenIds.add(childId)) { |
|||
log.info("Added Relation: {}", childId); |
|||
} |
|||
} |
|||
} |
|||
List<ListenableFuture<Set<EntityRelation>>> futures = new ArrayList<>(); |
|||
for (EntityId entityId : childrenIds) { |
|||
futures.add(findRelationsRecursively(entityId, direction, lvl, uniqueMap)); |
|||
} |
|||
//TODO: try to remove this blocking operation
|
|||
List<Set<EntityRelation>> relations = Futures.successfulAsList(futures).get(); |
|||
relations.forEach(r -> r.forEach(d -> children.add(d))); |
|||
return Futures.immediateFuture(children); |
|||
} |
|||
|
|||
private ListenableFuture<List<EntityRelation>> findRelations(final EntityId rootId, final EntitySearchDirection direction) { |
|||
ListenableFuture<List<EntityRelation>> relations; |
|||
if (direction == EntitySearchDirection.FROM) { |
|||
relations = findByFrom(rootId); |
|||
} else { |
|||
relations = findByTo(rootId); |
|||
} |
|||
return relations; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.relation; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* Created by ashvayka on 02.05.17. |
|||
*/ |
|||
@Data |
|||
public class EntityRelationsQuery { |
|||
|
|||
private RelationsSearchParameters parameters; |
|||
private List<EntityTypeFilter> filters; |
|||
|
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.relation; |
|||
|
|||
/** |
|||
* Created by ashvayka on 02.05.17. |
|||
*/ |
|||
public enum EntitySearchDirection { |
|||
|
|||
FROM, TO; |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.relation; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
|
|||
import javax.annotation.Nullable; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* Created by ashvayka on 02.05.17. |
|||
*/ |
|||
@Data |
|||
@AllArgsConstructor |
|||
public class EntityTypeFilter { |
|||
@Nullable |
|||
private String relationType; |
|||
@Nullable |
|||
private List<EntityType> entityTypes; |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.relation; |
|||
|
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.relation.EntityRelation; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* Created by ashvayka on 25.04.17. |
|||
*/ |
|||
public interface RelationDao { |
|||
|
|||
ListenableFuture<List<EntityRelation>> findAllByFrom(EntityId from); |
|||
|
|||
ListenableFuture<List<EntityRelation>> findAllByFromAndType(EntityId from, String relationType); |
|||
|
|||
ListenableFuture<List<EntityRelation>> findAllByTo(EntityId to); |
|||
|
|||
ListenableFuture<List<EntityRelation>> findAllByToAndType(EntityId to, String relationType); |
|||
|
|||
ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType); |
|||
|
|||
ListenableFuture<Boolean> saveRelation(EntityRelation relation); |
|||
|
|||
ListenableFuture<Boolean> deleteRelation(EntityRelation relation); |
|||
|
|||
ListenableFuture<Boolean> deleteRelation(EntityId from, EntityId to, String relationType); |
|||
|
|||
ListenableFuture<Boolean> deleteOutboundRelations(EntityId entity); |
|||
|
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.relation; |
|||
|
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.relation.EntityRelation; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* Created by ashvayka on 27.04.17. |
|||
*/ |
|||
public interface RelationService { |
|||
|
|||
ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType); |
|||
|
|||
ListenableFuture<Boolean> saveRelation(EntityRelation relation); |
|||
|
|||
ListenableFuture<Boolean> deleteRelation(EntityRelation relation); |
|||
|
|||
ListenableFuture<Boolean> deleteRelation(EntityId from, EntityId to, String relationType); |
|||
|
|||
ListenableFuture<Boolean> deleteEntityRelations(EntityId entity); |
|||
|
|||
ListenableFuture<List<EntityRelation>> findByFrom(EntityId from); |
|||
|
|||
ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType); |
|||
|
|||
ListenableFuture<List<EntityRelation>> findByTo(EntityId to); |
|||
|
|||
ListenableFuture<List<EntityRelation>> findByToAndType(EntityId to, String relationType); |
|||
|
|||
ListenableFuture<List<EntityRelation>> findByQuery(EntityRelationsQuery query); |
|||
|
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.relation; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
/** |
|||
* Created by ashvayka on 03.05.17. |
|||
*/ |
|||
@Data |
|||
@AllArgsConstructor |
|||
public class RelationsSearchParameters { |
|||
|
|||
private UUID rootId; |
|||
private EntityType rootType; |
|||
private EntitySearchDirection direction; |
|||
private int maxLevel = 1; |
|||
|
|||
public RelationsSearchParameters(EntityId entityId, EntitySearchDirection direction, int maxLevel) { |
|||
this.rootId = entityId.getId(); |
|||
this.rootType = entityId.getEntityType(); |
|||
this.direction = direction; |
|||
this.maxLevel = maxLevel; |
|||
} |
|||
|
|||
public EntityId getEntityId() { |
|||
return EntityIdFactory.getByTypeAndUuid(rootType, rootId); |
|||
} |
|||
} |
|||
@ -0,0 +1,283 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.service; |
|||
|
|||
import com.datastax.driver.core.utils.UUIDs; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import org.junit.After; |
|||
import org.junit.Assert; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.relation.EntityRelation; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
import org.thingsboard.server.dao.relation.EntityRelationsQuery; |
|||
import org.thingsboard.server.dao.relation.EntitySearchDirection; |
|||
import org.thingsboard.server.dao.relation.EntityTypeFilter; |
|||
import org.thingsboard.server.dao.relation.RelationsSearchParameters; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.concurrent.ExecutionException; |
|||
|
|||
public class RelationServiceImplTest extends AbstractServiceTest { |
|||
|
|||
@Before |
|||
public void before() { |
|||
} |
|||
|
|||
@After |
|||
public void after() { |
|||
} |
|||
|
|||
@Test |
|||
public void testSaveRelation() throws ExecutionException, InterruptedException { |
|||
AssetId parentId = new AssetId(UUIDs.timeBased()); |
|||
AssetId childId = new AssetId(UUIDs.timeBased()); |
|||
|
|||
EntityRelation relation = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE); |
|||
|
|||
Assert.assertTrue(saveRelation(relation)); |
|||
|
|||
Assert.assertTrue(relationService.checkRelation(parentId, childId, EntityRelation.CONTAINS_TYPE).get()); |
|||
|
|||
Assert.assertFalse(relationService.checkRelation(parentId, childId, "NOT_EXISTING_TYPE").get()); |
|||
|
|||
Assert.assertFalse(relationService.checkRelation(childId, parentId, EntityRelation.CONTAINS_TYPE).get()); |
|||
|
|||
Assert.assertFalse(relationService.checkRelation(childId, parentId, "NOT_EXISTING_TYPE").get()); |
|||
} |
|||
|
|||
@Test |
|||
public void testDeleteRelation() throws ExecutionException, InterruptedException { |
|||
AssetId parentId = new AssetId(UUIDs.timeBased()); |
|||
AssetId childId = new AssetId(UUIDs.timeBased()); |
|||
AssetId subChildId = new AssetId(UUIDs.timeBased()); |
|||
|
|||
EntityRelation relationA = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE); |
|||
EntityRelation relationB = new EntityRelation(childId, subChildId, EntityRelation.CONTAINS_TYPE); |
|||
|
|||
saveRelation(relationA); |
|||
saveRelation(relationB); |
|||
|
|||
Assert.assertTrue(relationService.deleteRelation(relationA).get()); |
|||
|
|||
Assert.assertFalse(relationService.checkRelation(parentId, childId, EntityRelation.CONTAINS_TYPE).get()); |
|||
|
|||
Assert.assertTrue(relationService.checkRelation(childId, subChildId, EntityRelation.CONTAINS_TYPE).get()); |
|||
|
|||
Assert.assertTrue(relationService.deleteRelation(childId, subChildId, EntityRelation.CONTAINS_TYPE).get()); |
|||
} |
|||
|
|||
@Test |
|||
public void testDeleteEntityRelations() throws ExecutionException, InterruptedException { |
|||
AssetId parentId = new AssetId(UUIDs.timeBased()); |
|||
AssetId childId = new AssetId(UUIDs.timeBased()); |
|||
AssetId subChildId = new AssetId(UUIDs.timeBased()); |
|||
|
|||
EntityRelation relationA = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE); |
|||
EntityRelation relationB = new EntityRelation(childId, subChildId, EntityRelation.CONTAINS_TYPE); |
|||
|
|||
saveRelation(relationA); |
|||
saveRelation(relationB); |
|||
|
|||
Assert.assertTrue(relationService.deleteEntityRelations(childId).get()); |
|||
|
|||
Assert.assertFalse(relationService.checkRelation(parentId, childId, EntityRelation.CONTAINS_TYPE).get()); |
|||
|
|||
Assert.assertFalse(relationService.checkRelation(childId, subChildId, EntityRelation.CONTAINS_TYPE).get()); |
|||
} |
|||
|
|||
@Test |
|||
public void testFindFrom() throws ExecutionException, InterruptedException { |
|||
AssetId parentA = new AssetId(UUIDs.timeBased()); |
|||
AssetId parentB = new AssetId(UUIDs.timeBased()); |
|||
AssetId childA = new AssetId(UUIDs.timeBased()); |
|||
AssetId childB = new AssetId(UUIDs.timeBased()); |
|||
|
|||
EntityRelation relationA1 = new EntityRelation(parentA, childA, EntityRelation.CONTAINS_TYPE); |
|||
EntityRelation relationA2 = new EntityRelation(parentA, childB, EntityRelation.CONTAINS_TYPE); |
|||
|
|||
EntityRelation relationB1 = new EntityRelation(parentB, childA, EntityRelation.MANAGES_TYPE); |
|||
EntityRelation relationB2 = new EntityRelation(parentB, childB, EntityRelation.MANAGES_TYPE); |
|||
|
|||
saveRelation(relationA1); |
|||
saveRelation(relationA2); |
|||
|
|||
saveRelation(relationB1); |
|||
saveRelation(relationB2); |
|||
|
|||
List<EntityRelation> relations = relationService.findByFrom(parentA).get(); |
|||
Assert.assertEquals(2, relations.size()); |
|||
for (EntityRelation relation : relations) { |
|||
Assert.assertEquals(EntityRelation.CONTAINS_TYPE, relation.getType()); |
|||
Assert.assertEquals(parentA, relation.getFrom()); |
|||
Assert.assertTrue(childA.equals(relation.getTo()) || childB.equals(relation.getTo())); |
|||
} |
|||
|
|||
relations = relationService.findByFromAndType(parentA, EntityRelation.CONTAINS_TYPE).get(); |
|||
Assert.assertEquals(2, relations.size()); |
|||
|
|||
relations = relationService.findByFromAndType(parentA, EntityRelation.MANAGES_TYPE).get(); |
|||
Assert.assertEquals(0, relations.size()); |
|||
|
|||
relations = relationService.findByFrom(parentB).get(); |
|||
Assert.assertEquals(2, relations.size()); |
|||
for (EntityRelation relation : relations) { |
|||
Assert.assertEquals(EntityRelation.MANAGES_TYPE, relation.getType()); |
|||
Assert.assertEquals(parentB, relation.getFrom()); |
|||
Assert.assertTrue(childA.equals(relation.getTo()) || childB.equals(relation.getTo())); |
|||
} |
|||
|
|||
relations = relationService.findByFromAndType(parentB, EntityRelation.CONTAINS_TYPE).get(); |
|||
Assert.assertEquals(0, relations.size()); |
|||
|
|||
relations = relationService.findByFromAndType(parentB, EntityRelation.CONTAINS_TYPE).get(); |
|||
Assert.assertEquals(0, relations.size()); |
|||
} |
|||
|
|||
private Boolean saveRelation(EntityRelation relationA1) throws ExecutionException, InterruptedException { |
|||
return relationService.saveRelation(relationA1).get(); |
|||
} |
|||
|
|||
@Test |
|||
public void testFindTo() throws ExecutionException, InterruptedException { |
|||
AssetId parentA = new AssetId(UUIDs.timeBased()); |
|||
AssetId parentB = new AssetId(UUIDs.timeBased()); |
|||
AssetId childA = new AssetId(UUIDs.timeBased()); |
|||
AssetId childB = new AssetId(UUIDs.timeBased()); |
|||
|
|||
EntityRelation relationA1 = new EntityRelation(parentA, childA, EntityRelation.CONTAINS_TYPE); |
|||
EntityRelation relationA2 = new EntityRelation(parentA, childB, EntityRelation.CONTAINS_TYPE); |
|||
|
|||
EntityRelation relationB1 = new EntityRelation(parentB, childA, EntityRelation.MANAGES_TYPE); |
|||
EntityRelation relationB2 = new EntityRelation(parentB, childB, EntityRelation.MANAGES_TYPE); |
|||
|
|||
saveRelation(relationA1); |
|||
saveRelation(relationA2); |
|||
|
|||
saveRelation(relationB1); |
|||
saveRelation(relationB2); |
|||
|
|||
// Data propagation to views is async
|
|||
Thread.sleep(3000); |
|||
|
|||
List<EntityRelation> relations = relationService.findByTo(childA).get(); |
|||
Assert.assertEquals(2, relations.size()); |
|||
for (EntityRelation relation : relations) { |
|||
Assert.assertEquals(childA, relation.getTo()); |
|||
Assert.assertTrue(parentA.equals(relation.getFrom()) || parentB.equals(relation.getFrom())); |
|||
} |
|||
|
|||
relations = relationService.findByToAndType(childA, EntityRelation.CONTAINS_TYPE).get(); |
|||
Assert.assertEquals(1, relations.size()); |
|||
|
|||
relations = relationService.findByToAndType(childB, EntityRelation.MANAGES_TYPE).get(); |
|||
Assert.assertEquals(1, relations.size()); |
|||
|
|||
relations = relationService.findByToAndType(parentA, EntityRelation.MANAGES_TYPE).get(); |
|||
Assert.assertEquals(0, relations.size()); |
|||
|
|||
relations = relationService.findByToAndType(parentB, EntityRelation.MANAGES_TYPE).get(); |
|||
Assert.assertEquals(0, relations.size()); |
|||
|
|||
relations = relationService.findByTo(childB).get(); |
|||
Assert.assertEquals(2, relations.size()); |
|||
for (EntityRelation relation : relations) { |
|||
Assert.assertEquals(childB, relation.getTo()); |
|||
Assert.assertTrue(parentA.equals(relation.getFrom()) || parentB.equals(relation.getFrom())); |
|||
} |
|||
} |
|||
|
|||
@Test |
|||
public void testCyclicRecursiveRelation() throws ExecutionException, InterruptedException { |
|||
// A -> B -> C -> A
|
|||
AssetId assetA = new AssetId(UUIDs.timeBased()); |
|||
AssetId assetB = new AssetId(UUIDs.timeBased()); |
|||
AssetId assetC = new AssetId(UUIDs.timeBased()); |
|||
|
|||
EntityRelation relationA = new EntityRelation(assetA, assetB, EntityRelation.CONTAINS_TYPE); |
|||
EntityRelation relationB = new EntityRelation(assetB, assetC, EntityRelation.CONTAINS_TYPE); |
|||
EntityRelation relationC = new EntityRelation(assetC, assetA, EntityRelation.CONTAINS_TYPE); |
|||
|
|||
saveRelation(relationA); |
|||
saveRelation(relationB); |
|||
saveRelation(relationC); |
|||
|
|||
EntityRelationsQuery query = new EntityRelationsQuery(); |
|||
query.setParameters(new RelationsSearchParameters(assetA, EntitySearchDirection.FROM, -1)); |
|||
query.setFilters(Collections.singletonList(new EntityTypeFilter(EntityRelation.CONTAINS_TYPE, Collections.singletonList(EntityType.ASSET)))); |
|||
List<EntityRelation> relations = relationService.findByQuery(query).get(); |
|||
Assert.assertEquals(3, relations.size()); |
|||
Assert.assertTrue(relations.contains(relationA)); |
|||
Assert.assertTrue(relations.contains(relationB)); |
|||
Assert.assertTrue(relations.contains(relationC)); |
|||
} |
|||
|
|||
@Test |
|||
public void testRecursiveRelation() throws ExecutionException, InterruptedException { |
|||
// A -> B -> [C,D]
|
|||
AssetId assetA = new AssetId(UUIDs.timeBased()); |
|||
AssetId assetB = new AssetId(UUIDs.timeBased()); |
|||
AssetId assetC = new AssetId(UUIDs.timeBased()); |
|||
DeviceId deviceD = new DeviceId(UUIDs.timeBased()); |
|||
|
|||
EntityRelation relationAB = new EntityRelation(assetA, assetB, EntityRelation.CONTAINS_TYPE); |
|||
EntityRelation relationBC = new EntityRelation(assetB, assetC, EntityRelation.CONTAINS_TYPE); |
|||
EntityRelation relationBD = new EntityRelation(assetB, deviceD, EntityRelation.CONTAINS_TYPE); |
|||
|
|||
|
|||
saveRelation(relationAB); |
|||
saveRelation(relationBC); |
|||
saveRelation(relationBD); |
|||
|
|||
EntityRelationsQuery query = new EntityRelationsQuery(); |
|||
query.setParameters(new RelationsSearchParameters(assetA, EntitySearchDirection.FROM, -1)); |
|||
query.setFilters(Collections.singletonList(new EntityTypeFilter(EntityRelation.CONTAINS_TYPE, Collections.singletonList(EntityType.ASSET)))); |
|||
List<EntityRelation> relations = relationService.findByQuery(query).get(); |
|||
Assert.assertEquals(2, relations.size()); |
|||
Assert.assertTrue(relations.contains(relationAB)); |
|||
Assert.assertTrue(relations.contains(relationBC)); |
|||
} |
|||
|
|||
|
|||
@Test(expected = DataValidationException.class) |
|||
public void testSaveRelationWithEmptyFrom() throws ExecutionException, InterruptedException { |
|||
EntityRelation relation = new EntityRelation(); |
|||
relation.setTo(new AssetId(UUIDs.timeBased())); |
|||
relation.setType(EntityRelation.CONTAINS_TYPE); |
|||
Assert.assertTrue(saveRelation(relation)); |
|||
} |
|||
|
|||
@Test(expected = DataValidationException.class) |
|||
public void testSaveRelationWithEmptyTo() throws ExecutionException, InterruptedException { |
|||
EntityRelation relation = new EntityRelation(); |
|||
relation.setFrom(new AssetId(UUIDs.timeBased())); |
|||
relation.setType(EntityRelation.CONTAINS_TYPE); |
|||
Assert.assertTrue(saveRelation(relation)); |
|||
} |
|||
|
|||
@Test(expected = DataValidationException.class) |
|||
public void testSaveRelationWithEmptyType() throws ExecutionException, InterruptedException { |
|||
EntityRelation relation = new EntityRelation(); |
|||
relation.setFrom(new AssetId(UUIDs.timeBased())); |
|||
relation.setTo(new AssetId(UUIDs.timeBased())); |
|||
Assert.assertTrue(saveRelation(relation)); |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* Copyright © 2016-2017 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.extensions.core.plugin.telemetry.handlers; |
|||
|
|||
/** |
|||
* Created by ashvayka on 08.05.17. |
|||
*/ |
|||
public enum TelemetryFeature { |
|||
|
|||
ATTRIBUTES, TIMESERIES; |
|||
|
|||
public static TelemetryFeature forName(String name) { |
|||
return TelemetryFeature.valueOf(name.toUpperCase()); |
|||
} |
|||
|
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue