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