185 changed files with 10917 additions and 1354 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,51 @@ |
|||||
|
/** |
||||
|
* 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.AssetId; |
||||
|
import org.thingsboard.server.common.data.id.EntityId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 11.05.17. |
||||
|
*/ |
||||
|
@Data |
||||
|
public class Alarm extends BaseData<AlarmId> { |
||||
|
|
||||
|
private TenantId tenantId; |
||||
|
private String type; |
||||
|
private EntityId originator; |
||||
|
private AlarmSeverity severity; |
||||
|
private AlarmStatus status; |
||||
|
private long startTs; |
||||
|
private long endTs; |
||||
|
private long ackTs; |
||||
|
private long clearTs; |
||||
|
private JsonNode details; |
||||
|
private boolean propagate; |
||||
|
|
||||
|
public Alarm() { |
||||
|
super(); |
||||
|
} |
||||
|
|
||||
|
public Alarm(AlarmId id) { |
||||
|
super(id); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -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,34 @@ |
|||||
|
/** |
||||
|
* 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.id.TenantId; |
||||
|
import org.thingsboard.server.common.data.page.TimePageLink; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 11.05.17. |
||||
|
*/ |
||||
|
@Data |
||||
|
public class AlarmQuery { |
||||
|
|
||||
|
private TenantId tenantId; |
||||
|
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,33 @@ |
|||||
|
/** |
||||
|
* 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; |
||||
|
|
||||
|
public boolean isAck() { |
||||
|
return this == ACTIVE_ACK || this == CLEARED_ACK; |
||||
|
} |
||||
|
|
||||
|
public boolean isCleared() { |
||||
|
return this == CLEARED_ACK || this == CLEARED_UNACK; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -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,34 @@ |
|||||
|
/** |
||||
|
* 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.id.EntityId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.dao.Dao; |
||||
|
import org.thingsboard.server.dao.model.AlarmEntity; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 11.05.17. |
||||
|
*/ |
||||
|
public interface AlarmDao extends Dao<AlarmEntity> { |
||||
|
|
||||
|
ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type); |
||||
|
|
||||
|
AlarmEntity save(Alarm alarm); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
/** |
||||
|
* 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 lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.common.data.alarm.Alarm; |
||||
|
import org.thingsboard.server.common.data.id.EntityId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.dao.AbstractModelDao; |
||||
|
import org.thingsboard.server.dao.model.AlarmEntity; |
||||
|
|
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COLUMN_FAMILY_NAME; |
||||
|
|
||||
|
@Component |
||||
|
@Slf4j |
||||
|
public class AlarmDaoImpl extends AbstractModelDao<AlarmEntity> implements AlarmDao { |
||||
|
|
||||
|
@Override |
||||
|
protected Class<AlarmEntity> getColumnFamilyClass() { |
||||
|
return AlarmEntity.class; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected String getColumnFamilyName() { |
||||
|
return ALARM_COLUMN_FAMILY_NAME; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public AlarmEntity save(Alarm alarm) { |
||||
|
log.debug("Save asset [{}] ", alarm); |
||||
|
return save(new AlarmEntity(alarm)); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type) { |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
/** |
||||
|
* 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.id.EntityId; |
||||
|
import org.thingsboard.server.common.data.page.TimePageData; |
||||
|
|
||||
|
import java.util.Optional; |
||||
|
|
||||
|
/** |
||||
|
* Created by ashvayka on 11.05.17. |
||||
|
*/ |
||||
|
public interface AlarmService { |
||||
|
|
||||
|
Alarm createOrUpdateAlarm(Alarm alarm); |
||||
|
|
||||
|
ListenableFuture<Boolean> updateAlarm(Alarm alarm); |
||||
|
|
||||
|
ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTs); |
||||
|
|
||||
|
ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long ackTs); |
||||
|
|
||||
|
ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,266 @@ |
|||||
|
/** |
||||
|
* 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.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.alarm.Alarm; |
||||
|
import org.thingsboard.server.common.data.alarm.AlarmId; |
||||
|
import org.thingsboard.server.common.data.alarm.AlarmQuery; |
||||
|
import org.thingsboard.server.common.data.alarm.AlarmStatus; |
||||
|
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.page.TimePageData; |
||||
|
import org.thingsboard.server.common.data.relation.EntityRelation; |
||||
|
import org.thingsboard.server.dao.asset.AssetDao; |
||||
|
import org.thingsboard.server.dao.asset.AssetSearchQuery; |
||||
|
import org.thingsboard.server.dao.asset.AssetService; |
||||
|
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.AlarmEntity; |
||||
|
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.relation.RelationService; |
||||
|
import org.thingsboard.server.dao.relation.RelationsSearchParameters; |
||||
|
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.Collections; |
||||
|
import java.util.List; |
||||
|
import java.util.Optional; |
||||
|
import java.util.concurrent.ExecutionException; |
||||
|
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 BaseAlarmService extends BaseEntityService implements AlarmService { |
||||
|
|
||||
|
private static final String ALARM_RELATION_PREFIX = "ALARM_"; |
||||
|
private static final String ALARM_RELATION = "ALARM_ANY"; |
||||
|
|
||||
|
@Autowired |
||||
|
private AlarmDao alarmDao; |
||||
|
|
||||
|
@Autowired |
||||
|
private TenantDao tenantDao; |
||||
|
|
||||
|
@Autowired |
||||
|
private RelationService relationService; |
||||
|
|
||||
|
@Override |
||||
|
public Alarm createOrUpdateAlarm(Alarm alarm) { |
||||
|
alarmDataValidator.validate(alarm); |
||||
|
try { |
||||
|
if (alarm.getStartTs() == 0L) { |
||||
|
alarm.setStartTs(System.currentTimeMillis()); |
||||
|
} |
||||
|
Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get(); |
||||
|
if (existing == null || existing.getStatus().isCleared()) { |
||||
|
log.debug("New Alarm : {}", alarm); |
||||
|
Alarm saved = getData(alarmDao.save(new AlarmEntity(alarm))); |
||||
|
EntityRelationsQuery query = new EntityRelationsQuery(); |
||||
|
query.setParameters(new RelationsSearchParameters(saved.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE)); |
||||
|
List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList()); |
||||
|
for (EntityId parentId : parentEntities) { |
||||
|
createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION)); |
||||
|
createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name())); |
||||
|
} |
||||
|
return saved; |
||||
|
} else { |
||||
|
log.debug("Alarm before merge: {}", alarm); |
||||
|
alarm = merge(existing, alarm); |
||||
|
log.debug("Alarm after merge: {}", alarm); |
||||
|
return getData(alarmDao.save(new AlarmEntity(alarm))); |
||||
|
} |
||||
|
} catch (ExecutionException | InterruptedException e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<Boolean> updateAlarm(Alarm update) { |
||||
|
alarmDataValidator.validate(update); |
||||
|
return getAndUpdate(update.getId(), new Function<AlarmEntity, Boolean>() { |
||||
|
@Nullable |
||||
|
@Override |
||||
|
public Boolean apply(@Nullable AlarmEntity entity) { |
||||
|
Alarm alarm = getData(entity); |
||||
|
if (alarm == null) { |
||||
|
return false; |
||||
|
} else { |
||||
|
AlarmStatus oldStatus = alarm.getStatus(); |
||||
|
AlarmStatus newStatus = update.getStatus(); |
||||
|
alarmDao.save(new AlarmEntity(merge(alarm, update))); |
||||
|
if (oldStatus != newStatus) { |
||||
|
updateRelations(alarm, oldStatus, newStatus); |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTime) { |
||||
|
return getAndUpdate(alarmId, new Function<AlarmEntity, Boolean>() { |
||||
|
@Nullable |
||||
|
@Override |
||||
|
public Boolean apply(@Nullable AlarmEntity entity) { |
||||
|
Alarm alarm = getData(entity); |
||||
|
if (alarm == null || alarm.getStatus().isAck()) { |
||||
|
return false; |
||||
|
} else { |
||||
|
AlarmStatus oldStatus = alarm.getStatus(); |
||||
|
AlarmStatus newStatus = oldStatus.isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK; |
||||
|
alarm.setStatus(newStatus); |
||||
|
alarm.setAckTs(ackTime); |
||||
|
alarmDao.save(new AlarmEntity(alarm)); |
||||
|
updateRelations(alarm, oldStatus, newStatus); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long clearTime) { |
||||
|
return getAndUpdate(alarmId, new Function<AlarmEntity, Boolean>() { |
||||
|
@Nullable |
||||
|
@Override |
||||
|
public Boolean apply(@Nullable AlarmEntity entity) { |
||||
|
Alarm alarm = getData(entity); |
||||
|
if (alarm == null || alarm.getStatus().isCleared()) { |
||||
|
return false; |
||||
|
} else { |
||||
|
AlarmStatus oldStatus = alarm.getStatus(); |
||||
|
AlarmStatus newStatus = oldStatus.isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK; |
||||
|
alarm.setStatus(newStatus); |
||||
|
alarm.setClearTs(clearTime); |
||||
|
alarmDao.save(new AlarmEntity(alarm)); |
||||
|
updateRelations(alarm, oldStatus, newStatus); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query) { |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
private void deleteRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException { |
||||
|
log.debug("Deleting Alarm relation: {}", alarmRelation); |
||||
|
relationService.deleteRelation(alarmRelation).get(); |
||||
|
} |
||||
|
|
||||
|
private void createRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException { |
||||
|
log.debug("Creating Alarm relation: {}", alarmRelation); |
||||
|
relationService.saveRelation(alarmRelation).get(); |
||||
|
} |
||||
|
|
||||
|
private Alarm merge(Alarm existing, Alarm alarm) { |
||||
|
if (alarm.getStartTs() > existing.getEndTs()) { |
||||
|
existing.setEndTs(alarm.getStartTs()); |
||||
|
} |
||||
|
if (alarm.getEndTs() > existing.getEndTs()) { |
||||
|
existing.setEndTs(alarm.getEndTs()); |
||||
|
} |
||||
|
if (alarm.getClearTs() > existing.getClearTs()) { |
||||
|
existing.setClearTs(alarm.getClearTs()); |
||||
|
} |
||||
|
if (alarm.getAckTs() > existing.getAckTs()) { |
||||
|
existing.setAckTs(alarm.getAckTs()); |
||||
|
} |
||||
|
existing.setStatus(alarm.getStatus()); |
||||
|
existing.setSeverity(alarm.getSeverity()); |
||||
|
existing.setDetails(alarm.getDetails()); |
||||
|
return existing; |
||||
|
} |
||||
|
|
||||
|
private void updateRelations(Alarm alarm, AlarmStatus oldStatus, AlarmStatus newStatus) { |
||||
|
try { |
||||
|
EntityRelationsQuery query = new EntityRelationsQuery(); |
||||
|
query.setParameters(new RelationsSearchParameters(alarm.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE)); |
||||
|
List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList()); |
||||
|
for (EntityId parentId : parentEntities) { |
||||
|
deleteRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + oldStatus.name())); |
||||
|
createRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + newStatus.name())); |
||||
|
} |
||||
|
} catch (ExecutionException | InterruptedException e) { |
||||
|
log.warn("[{}] Failed to update relations. Old status: [{}], New status: [{}]", alarm.getId(), oldStatus, newStatus); |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private ListenableFuture<Boolean> getAndUpdate(AlarmId alarmId, Function<AlarmEntity, Boolean> function) { |
||||
|
validateId(alarmId, "Alarm id should be specified!"); |
||||
|
ListenableFuture<AlarmEntity> entity = alarmDao.findByIdAsync(alarmId.getId()); |
||||
|
return Futures.transform(entity, function); |
||||
|
} |
||||
|
|
||||
|
private DataValidator<Alarm> alarmDataValidator = |
||||
|
new DataValidator<Alarm>() { |
||||
|
|
||||
|
@Override |
||||
|
protected void validateDataImpl(Alarm alarm) { |
||||
|
if (StringUtils.isEmpty(alarm.getType())) { |
||||
|
throw new DataValidationException("Alarm type should be specified!"); |
||||
|
} |
||||
|
if (alarm.getOriginator() == null) { |
||||
|
throw new DataValidationException("Alarm originator should be specified!"); |
||||
|
} |
||||
|
if (alarm.getSeverity() == null) { |
||||
|
throw new DataValidationException("Alarm severity should be specified!"); |
||||
|
} |
||||
|
if (alarm.getStatus() == null) { |
||||
|
throw new DataValidationException("Alarm status should be specified!"); |
||||
|
} |
||||
|
if (alarm.getTenantId() == null) { |
||||
|
throw new DataValidationException("Alarm should be assigned to tenant!"); |
||||
|
} else { |
||||
|
TenantEntity tenant = tenantDao.findById(alarm.getTenantId().getId()); |
||||
|
if (tenant == null) { |
||||
|
throw new DataValidationException("Alarm is referencing to non-existent tenant!"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
@ -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,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,148 @@ |
|||||
|
/** |
||||
|
* 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.*; |
||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||
|
import org.thingsboard.server.common.data.EntityType; |
||||
|
import org.thingsboard.server.common.data.alarm.Alarm; |
||||
|
import org.thingsboard.server.common.data.alarm.AlarmId; |
||||
|
import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
||||
|
import org.thingsboard.server.common.data.alarm.AlarmStatus; |
||||
|
import org.thingsboard.server.common.data.id.EntityIdFactory; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.dao.model.type.AlarmSeverityCodec; |
||||
|
import org.thingsboard.server.dao.model.type.AlarmStatusCodec; |
||||
|
import org.thingsboard.server.dao.model.type.EntityTypeCodec; |
||||
|
import org.thingsboard.server.dao.model.type.JsonCodec; |
||||
|
|
||||
|
import java.util.UUID; |
||||
|
|
||||
|
import static org.thingsboard.server.dao.model.ModelConstants.*; |
||||
|
|
||||
|
@Table(name = ALARM_COLUMN_FAMILY_NAME) |
||||
|
public final class AlarmEntity implements BaseEntity<Alarm> { |
||||
|
|
||||
|
@Transient |
||||
|
private static final long serialVersionUID = -1265181166886910152L; |
||||
|
|
||||
|
@ClusteringColumn(value = 1) |
||||
|
@Column(name = ID_PROPERTY) |
||||
|
private UUID id; |
||||
|
|
||||
|
@PartitionKey(value = 0) |
||||
|
@Column(name = ALARM_TENANT_ID_PROPERTY) |
||||
|
private UUID tenantId; |
||||
|
|
||||
|
@PartitionKey(value = 1) |
||||
|
@Column(name = ALARM_ORIGINATOR_ID_PROPERTY) |
||||
|
private UUID originatorId; |
||||
|
|
||||
|
@PartitionKey(value = 2) |
||||
|
@Column(name = ALARM_ORIGINATOR_TYPE_PROPERTY, codec = EntityTypeCodec.class) |
||||
|
private EntityType originatorType; |
||||
|
|
||||
|
@ClusteringColumn(value = 0) |
||||
|
@Column(name = ALARM_TYPE_PROPERTY) |
||||
|
private String type; |
||||
|
|
||||
|
@Column(name = ALARM_SEVERITY_PROPERTY, codec = AlarmSeverityCodec.class) |
||||
|
private AlarmSeverity severity; |
||||
|
|
||||
|
@Column(name = ALARM_STATUS_PROPERTY, codec = AlarmStatusCodec.class) |
||||
|
private AlarmStatus status; |
||||
|
|
||||
|
@Column(name = ALARM_START_TS_PROPERTY) |
||||
|
private Long startTs; |
||||
|
|
||||
|
@Column(name = ALARM_END_TS_PROPERTY) |
||||
|
private Long endTs; |
||||
|
|
||||
|
@Column(name = ALARM_ACK_TS_PROPERTY) |
||||
|
private Long ackTs; |
||||
|
|
||||
|
@Column(name = ALARM_CLEAR_TS_PROPERTY) |
||||
|
private Long clearTs; |
||||
|
|
||||
|
@Column(name = ALARM_DETAILS_PROPERTY, codec = JsonCodec.class) |
||||
|
private JsonNode details; |
||||
|
|
||||
|
@Column(name = ALARM_PROPAGATE_PROPERTY) |
||||
|
private Boolean propagate; |
||||
|
|
||||
|
public AlarmEntity() { |
||||
|
super(); |
||||
|
} |
||||
|
|
||||
|
public AlarmEntity(Alarm alarm) { |
||||
|
if (alarm.getId() != null) { |
||||
|
this.id = alarm.getId().getId(); |
||||
|
} |
||||
|
if (alarm.getTenantId() != null) { |
||||
|
this.tenantId = alarm.getTenantId().getId(); |
||||
|
} |
||||
|
this.type = alarm.getType(); |
||||
|
this.originatorId = alarm.getOriginator().getId(); |
||||
|
this.originatorType = alarm.getOriginator().getEntityType(); |
||||
|
this.type = alarm.getType(); |
||||
|
this.severity = alarm.getSeverity(); |
||||
|
this.status = alarm.getStatus(); |
||||
|
this.propagate = alarm.isPropagate(); |
||||
|
this.startTs = alarm.getStartTs(); |
||||
|
this.endTs = alarm.getEndTs(); |
||||
|
this.ackTs = alarm.getAckTs(); |
||||
|
this.clearTs = alarm.getClearTs(); |
||||
|
this.details = alarm.getDetails(); |
||||
|
} |
||||
|
|
||||
|
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; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Alarm toData() { |
||||
|
Alarm alarm = new Alarm(new AlarmId(id)); |
||||
|
alarm.setCreatedTime(UUIDs.unixTimestamp(id)); |
||||
|
if (tenantId != null) { |
||||
|
alarm.setTenantId(new TenantId(tenantId)); |
||||
|
} |
||||
|
alarm.setOriginator(EntityIdFactory.getByTypeAndUuid(originatorType, originatorId)); |
||||
|
alarm.setType(type); |
||||
|
alarm.setSeverity(severity); |
||||
|
alarm.setStatus(status); |
||||
|
alarm.setPropagate(propagate); |
||||
|
alarm.setStartTs(startTs); |
||||
|
alarm.setEndTs(endTs); |
||||
|
alarm.setAckTs(ackTs); |
||||
|
alarm.setClearTs(clearTs); |
||||
|
alarm.setDetails(details); |
||||
|
return alarm; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -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,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.dao.model.type; |
||||
|
|
||||
|
import com.datastax.driver.extras.codecs.enums.EnumNameCodec; |
||||
|
import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
||||
|
import org.thingsboard.server.common.data.alarm.AlarmStatus; |
||||
|
import org.thingsboard.server.dao.alarm.AlarmService; |
||||
|
|
||||
|
public class AlarmSeverityCodec extends EnumNameCodec<AlarmSeverity> { |
||||
|
|
||||
|
public AlarmSeverityCodec() { |
||||
|
super(AlarmSeverity.class); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
/** |
||||
|
* 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.type; |
||||
|
|
||||
|
import com.datastax.driver.extras.codecs.enums.EnumNameCodec; |
||||
|
import org.thingsboard.server.common.data.alarm.AlarmStatus; |
||||
|
|
||||
|
public class AlarmStatusCodec extends EnumNameCodec<AlarmStatus> { |
||||
|
|
||||
|
public AlarmStatusCodec() { |
||||
|
super(AlarmStatus.class); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -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,261 @@ |
|||||
|
/** |
||||
|
* 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.debug("Filters are not set [{}]", query); |
||||
|
} |
||||
|
|
||||
|
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) { |
||||
|
if (filters == null || filters.isEmpty()) { |
||||
|
relations.add(relation); |
||||
|
} else { |
||||
|
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,52 @@ |
|||||
|
/** |
||||
|
* 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); |
||||
|
|
||||
|
// TODO: This method may be useful for some validations in the future
|
||||
|
// ListenableFuture<Boolean> checkRecursiveRelation(EntityId from, EntityId to);
|
||||
|
|
||||
|
} |
||||
@ -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()); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,261 @@ |
|||||
|
/* |
||||
|
* 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. |
||||
|
*/ |
||||
|
export default angular.module('thingsboard.api.asset', []) |
||||
|
.factory('assetService', AssetService) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function AssetService($http, $q, customerService, userService) { |
||||
|
|
||||
|
var service = { |
||||
|
getAsset: getAsset, |
||||
|
getAssets: getAssets, |
||||
|
saveAsset: saveAsset, |
||||
|
deleteAsset: deleteAsset, |
||||
|
assignAssetToCustomer: assignAssetToCustomer, |
||||
|
unassignAssetFromCustomer: unassignAssetFromCustomer, |
||||
|
makeAssetPublic: makeAssetPublic, |
||||
|
getTenantAssets: getTenantAssets, |
||||
|
getCustomerAssets: getCustomerAssets, |
||||
|
findByQuery: findByQuery, |
||||
|
fetchAssetsByNameFilter: fetchAssetsByNameFilter |
||||
|
} |
||||
|
|
||||
|
return service; |
||||
|
|
||||
|
function getAsset(assetId, ignoreErrors, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/asset/' + assetId; |
||||
|
if (!config) { |
||||
|
config = {}; |
||||
|
} |
||||
|
config = Object.assign(config, { ignoreErrors: ignoreErrors }); |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getAssets(assetIds, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var ids = ''; |
||||
|
for (var i=0;i<assetIds.length;i++) { |
||||
|
if (i>0) { |
||||
|
ids += ','; |
||||
|
} |
||||
|
ids += assetIds[i]; |
||||
|
} |
||||
|
var url = '/api/assets?assetIds=' + ids; |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
var assets = response.data; |
||||
|
assets.sort(function (asset1, asset2) { |
||||
|
var id1 = asset1.id.id; |
||||
|
var id2 = asset2.id.id; |
||||
|
var index1 = assetIds.indexOf(id1); |
||||
|
var index2 = assetIds.indexOf(id2); |
||||
|
return index1 - index2; |
||||
|
}); |
||||
|
deferred.resolve(assets); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function saveAsset(asset, ignoreErrors, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/asset'; |
||||
|
if (!config) { |
||||
|
config = {}; |
||||
|
} |
||||
|
config = Object.assign(config, { ignoreErrors: ignoreErrors }); |
||||
|
$http.post(url, asset, config).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function deleteAsset(assetId, ignoreErrors, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/asset/' + assetId; |
||||
|
if (!config) { |
||||
|
config = {}; |
||||
|
} |
||||
|
config = Object.assign(config, { ignoreErrors: ignoreErrors }); |
||||
|
$http.delete(url, config).then(function success() { |
||||
|
deferred.resolve(); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function assignAssetToCustomer(customerId, assetId, ignoreErrors, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/customer/' + customerId + '/asset/' + assetId; |
||||
|
if (!config) { |
||||
|
config = {}; |
||||
|
} |
||||
|
config = Object.assign(config, { ignoreErrors: ignoreErrors }); |
||||
|
$http.post(url, null, config).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function unassignAssetFromCustomer(assetId, ignoreErrors, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/customer/asset/' + assetId; |
||||
|
if (!config) { |
||||
|
config = {}; |
||||
|
} |
||||
|
config = Object.assign(config, { ignoreErrors: ignoreErrors }); |
||||
|
$http.delete(url, config).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function makeAssetPublic(assetId, ignoreErrors, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/customer/public/asset/' + assetId; |
||||
|
if (!config) { |
||||
|
config = {}; |
||||
|
} |
||||
|
config = Object.assign(config, { ignoreErrors: ignoreErrors }); |
||||
|
$http.post(url, null, config).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getTenantAssets(pageLink, applyCustomersInfo, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/tenant/assets?limit=' + pageLink.limit; |
||||
|
if (angular.isDefined(pageLink.textSearch)) { |
||||
|
url += '&textSearch=' + pageLink.textSearch; |
||||
|
} |
||||
|
if (angular.isDefined(pageLink.idOffset)) { |
||||
|
url += '&idOffset=' + pageLink.idOffset; |
||||
|
} |
||||
|
if (angular.isDefined(pageLink.textOffset)) { |
||||
|
url += '&textOffset=' + pageLink.textOffset; |
||||
|
} |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
if (applyCustomersInfo) { |
||||
|
customerService.applyAssignedCustomersInfo(response.data.data).then( |
||||
|
function success(data) { |
||||
|
response.data.data = data; |
||||
|
deferred.resolve(response.data); |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.reject(); |
||||
|
} |
||||
|
); |
||||
|
} else { |
||||
|
deferred.resolve(response.data); |
||||
|
} |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getCustomerAssets(customerId, pageLink, applyCustomersInfo, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/customer/' + customerId + '/assets?limit=' + pageLink.limit; |
||||
|
if (angular.isDefined(pageLink.textSearch)) { |
||||
|
url += '&textSearch=' + pageLink.textSearch; |
||||
|
} |
||||
|
if (angular.isDefined(pageLink.idOffset)) { |
||||
|
url += '&idOffset=' + pageLink.idOffset; |
||||
|
} |
||||
|
if (angular.isDefined(pageLink.textOffset)) { |
||||
|
url += '&textOffset=' + pageLink.textOffset; |
||||
|
} |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
if (applyCustomersInfo) { |
||||
|
customerService.applyAssignedCustomerInfo(response.data.data, customerId).then( |
||||
|
function success(data) { |
||||
|
response.data.data = data; |
||||
|
deferred.resolve(response.data); |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.reject(); |
||||
|
} |
||||
|
); |
||||
|
} else { |
||||
|
deferred.resolve(response.data); |
||||
|
} |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
|
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function findByQuery(query, ignoreErrors, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/assets'; |
||||
|
if (!config) { |
||||
|
config = {}; |
||||
|
} |
||||
|
config = Object.assign(config, { ignoreErrors: ignoreErrors }); |
||||
|
$http.post(url, query, config).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function fetchAssetsByNameFilter(assetNameFilter, limit, applyCustomersInfo, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var user = userService.getCurrentUser(); |
||||
|
var promise; |
||||
|
var pageLink = {limit: limit, textSearch: assetNameFilter}; |
||||
|
if (user.authority === 'CUSTOMER_USER') { |
||||
|
var customerId = user.customerId; |
||||
|
promise = getCustomerAssets(customerId, pageLink, applyCustomersInfo, config); |
||||
|
} else { |
||||
|
promise = getTenantAssets(pageLink, applyCustomersInfo, config); |
||||
|
} |
||||
|
promise.then( |
||||
|
function success(result) { |
||||
|
if (result.data && result.data.length > 0) { |
||||
|
deferred.resolve(result.data); |
||||
|
} else { |
||||
|
deferred.resolve(null); |
||||
|
} |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.resolve(null); |
||||
|
} |
||||
|
); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -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. |
||||
|
*/ |
||||
|
export default angular.module('thingsboard.api.attribute', []) |
||||
|
.factory('attributeService', AttributeService) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function AttributeService($http, $q, $filter, types, telemetryWebsocketService) { |
||||
|
|
||||
|
var entityAttributesSubscriptionMap = {}; |
||||
|
|
||||
|
var service = { |
||||
|
getEntityKeys: getEntityKeys, |
||||
|
getEntityTimeseriesValues: getEntityTimeseriesValues, |
||||
|
getEntityAttributes: getEntityAttributes, |
||||
|
subscribeForEntityAttributes: subscribeForEntityAttributes, |
||||
|
unsubscribeForEntityAttributes: unsubscribeForEntityAttributes, |
||||
|
saveEntityAttributes: saveEntityAttributes, |
||||
|
deleteEntityAttributes: deleteEntityAttributes |
||||
|
} |
||||
|
|
||||
|
return service; |
||||
|
|
||||
|
function getEntityKeys(entityType, entityId, query, type) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/'; |
||||
|
if (type === types.dataKeyType.timeseries) { |
||||
|
url += 'timeseries'; |
||||
|
} else if (type === types.dataKeyType.attribute) { |
||||
|
url += 'attributes'; |
||||
|
} |
||||
|
$http.get(url, null).then(function success(response) { |
||||
|
var result = []; |
||||
|
if (response.data) { |
||||
|
if (query) { |
||||
|
var dataKeys = response.data; |
||||
|
var lowercaseQuery = angular.lowercase(query); |
||||
|
for (var i=0; i<dataKeys.length;i++) { |
||||
|
if (angular.lowercase(dataKeys[i]).indexOf(lowercaseQuery) === 0) { |
||||
|
result.push(dataKeys[i]); |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
result = response.data; |
||||
|
} |
||||
|
} |
||||
|
deferred.resolve(result); |
||||
|
}, function fail(response) { |
||||
|
deferred.reject(response.data); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getEntityTimeseriesValues(entityType, entityId, keys, startTs, endTs, limit) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/values/timeseries'; |
||||
|
url += '?keys=' + keys; |
||||
|
url += '&startTs=' + startTs; |
||||
|
url += '&endTs=' + endTs; |
||||
|
if (angular.isDefined(limit)) { |
||||
|
url += '&limit=' + limit; |
||||
|
} |
||||
|
$http.get(url, null).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail(response) { |
||||
|
deferred.reject(response.data); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function processAttributes(attributes, query, deferred, successCallback, update, apply) { |
||||
|
attributes = $filter('orderBy')(attributes, query.order); |
||||
|
if (query.search != null) { |
||||
|
attributes = $filter('filter')(attributes, {key: query.search}); |
||||
|
} |
||||
|
var responseData = { |
||||
|
count: attributes.length |
||||
|
} |
||||
|
var startIndex = query.limit * (query.page - 1); |
||||
|
responseData.data = attributes.slice(startIndex, startIndex + query.limit); |
||||
|
successCallback(responseData, update, apply); |
||||
|
if (deferred) { |
||||
|
deferred.resolve(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function getEntityAttributes(entityType, entityId, attributeScope, query, successCallback, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var subscriptionId = entityType + entityId + attributeScope; |
||||
|
var eas = entityAttributesSubscriptionMap[subscriptionId]; |
||||
|
if (eas) { |
||||
|
if (eas.attributes) { |
||||
|
processAttributes(eas.attributes, query, deferred, successCallback); |
||||
|
eas.subscriptionCallback = function(attributes) { |
||||
|
processAttributes(attributes, query, null, successCallback, true, true); |
||||
|
} |
||||
|
} else { |
||||
|
eas.subscriptionCallback = function(attributes) { |
||||
|
processAttributes(attributes, query, deferred, successCallback, false, true); |
||||
|
eas.subscriptionCallback = function(attributes) { |
||||
|
processAttributes(attributes, query, null, successCallback, true, true); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/values/attributes/' + attributeScope; |
||||
|
$http.get(url, config).then(function success(response) { |
||||
|
processAttributes(response.data, query, deferred, successCallback); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
} |
||||
|
return deferred; |
||||
|
} |
||||
|
|
||||
|
function onSubscriptionData(data, subscriptionId) { |
||||
|
var entityAttributesSubscription = entityAttributesSubscriptionMap[subscriptionId]; |
||||
|
if (entityAttributesSubscription) { |
||||
|
if (!entityAttributesSubscription.attributes) { |
||||
|
entityAttributesSubscription.attributes = []; |
||||
|
entityAttributesSubscription.keys = {}; |
||||
|
} |
||||
|
var attributes = entityAttributesSubscription.attributes; |
||||
|
var keys = entityAttributesSubscription.keys; |
||||
|
for (var key in data) { |
||||
|
var index = keys[key]; |
||||
|
var attribute; |
||||
|
if (index > -1) { |
||||
|
attribute = attributes[index]; |
||||
|
} else { |
||||
|
attribute = { |
||||
|
key: key |
||||
|
}; |
||||
|
index = attributes.push(attribute)-1; |
||||
|
keys[key] = index; |
||||
|
} |
||||
|
var attrData = data[key][0]; |
||||
|
attribute.lastUpdateTs = attrData[0]; |
||||
|
attribute.value = attrData[1]; |
||||
|
} |
||||
|
if (entityAttributesSubscription.subscriptionCallback) { |
||||
|
entityAttributesSubscription.subscriptionCallback(attributes); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function subscribeForEntityAttributes(entityType, entityId, attributeScope) { |
||||
|
var subscriptionId = entityType + entityId + attributeScope; |
||||
|
var entityAttributesSubscription = entityAttributesSubscriptionMap[subscriptionId]; |
||||
|
if (!entityAttributesSubscription) { |
||||
|
var subscriptionCommand = { |
||||
|
entityType: entityType, |
||||
|
entityId: entityId, |
||||
|
scope: attributeScope |
||||
|
}; |
||||
|
|
||||
|
var type = attributeScope === types.latestTelemetry.value ? |
||||
|
types.dataKeyType.timeseries : types.dataKeyType.attribute; |
||||
|
|
||||
|
var subscriber = { |
||||
|
subscriptionCommand: subscriptionCommand, |
||||
|
type: type, |
||||
|
onData: function (data) { |
||||
|
if (data.data) { |
||||
|
onSubscriptionData(data.data, subscriptionId); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
entityAttributesSubscription = { |
||||
|
subscriber: subscriber, |
||||
|
attributes: null |
||||
|
}; |
||||
|
entityAttributesSubscriptionMap[subscriptionId] = entityAttributesSubscription; |
||||
|
telemetryWebsocketService.subscribe(subscriber); |
||||
|
} |
||||
|
return subscriptionId; |
||||
|
} |
||||
|
|
||||
|
function unsubscribeForEntityAttributes(subscriptionId) { |
||||
|
var entityAttributesSubscription = entityAttributesSubscriptionMap[subscriptionId]; |
||||
|
if (entityAttributesSubscription) { |
||||
|
telemetryWebsocketService.unsubscribe(entityAttributesSubscription.subscriber); |
||||
|
delete entityAttributesSubscriptionMap[subscriptionId]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function saveEntityAttributes(entityType, entityId, attributeScope, attributes) { |
||||
|
var deferred = $q.defer(); |
||||
|
var attributesData = {}; |
||||
|
for (var a=0; a<attributes.length;a++) { |
||||
|
attributesData[attributes[a].key] = attributes[a].value; |
||||
|
} |
||||
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope; |
||||
|
$http.post(url, attributesData).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail(response) { |
||||
|
deferred.reject(response.data); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function deleteEntityAttributes(entityType, entityId, attributeScope, attributes) { |
||||
|
var deferred = $q.defer(); |
||||
|
var keys = ''; |
||||
|
for (var i = 0; i < attributes.length; i++) { |
||||
|
if (i > 0) { |
||||
|
keys += ','; |
||||
|
} |
||||
|
keys += attributes[i].key; |
||||
|
} |
||||
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope + '?keys=' + keys; |
||||
|
$http.delete(url).then(function success() { |
||||
|
deferred.resolve(); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,136 @@ |
|||||
|
/* |
||||
|
* 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. |
||||
|
*/ |
||||
|
export default angular.module('thingsboard.api.entityRelation', []) |
||||
|
.factory('entityRelationService', EntityRelationService) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function EntityRelationService($http, $q) { |
||||
|
|
||||
|
var service = { |
||||
|
saveRelation: saveRelation, |
||||
|
deleteRelation: deleteRelation, |
||||
|
deleteRelations: deleteRelations, |
||||
|
findByFrom: findByFrom, |
||||
|
findByFromAndType: findByFromAndType, |
||||
|
findByTo: findByTo, |
||||
|
findByToAndType: findByToAndType, |
||||
|
findByQuery: findByQuery |
||||
|
} |
||||
|
|
||||
|
return service; |
||||
|
|
||||
|
function saveRelation(relation) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/relation'; |
||||
|
$http.post(url, relation).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function deleteRelation(fromId, fromType, relationType, toId, toType) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/relation?fromId=' + fromId; |
||||
|
url += '&fromType=' + fromType; |
||||
|
url += '&relationType=' + relationType; |
||||
|
url += '&toId=' + toId; |
||||
|
url += '&toType=' + toType; |
||||
|
$http.delete(url).then(function success() { |
||||
|
deferred.resolve(); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function deleteRelations(entityId, entityType) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/relations?entityId=' + entityId; |
||||
|
url += '&entityType=' + entityType; |
||||
|
$http.delete(url).then(function success() { |
||||
|
deferred.resolve(); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
function findByFrom(fromId, fromType) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/relations?fromId=' + fromId; |
||||
|
url += '&fromType=' + fromType; |
||||
|
$http.get(url, null).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function findByFromAndType(fromId, fromType, relationType) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/relations?fromId=' + fromId; |
||||
|
url += '&fromType=' + fromType; |
||||
|
url += '&relationType=' + relationType; |
||||
|
$http.get(url, null).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function findByTo(toId, toType) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/relations?toId=' + toId; |
||||
|
url += '&toType=' + toType; |
||||
|
$http.get(url, null).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function findByToAndType(toId, toType, relationType) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/relations?toId=' + toId; |
||||
|
url += '&toType=' + toType; |
||||
|
url += '&relationType=' + relationType; |
||||
|
$http.get(url, null).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function findByQuery(query) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/relations'; |
||||
|
$http.post(url, query).then(function success(response) { |
||||
|
deferred.resolve(response.data); |
||||
|
}, function fail() { |
||||
|
deferred.reject(); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,477 @@ |
|||||
|
/* |
||||
|
* 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. |
||||
|
*/ |
||||
|
import thingsboardTypes from '../common/types.constant'; |
||||
|
|
||||
|
export default angular.module('thingsboard.api.entity', [thingsboardTypes]) |
||||
|
.factory('entityService', EntityService) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function EntityService($http, $q, userService, deviceService, |
||||
|
assetService, tenantService, customerService, |
||||
|
ruleService, pluginService, types, utils) { |
||||
|
var service = { |
||||
|
getEntity: getEntity, |
||||
|
getEntities: getEntities, |
||||
|
getEntitiesByNameFilter: getEntitiesByNameFilter, |
||||
|
entityName: entityName, |
||||
|
processEntityAliases: processEntityAliases, |
||||
|
getEntityKeys: getEntityKeys, |
||||
|
checkEntityAlias: checkEntityAlias, |
||||
|
createDatasoucesFromSubscriptionsInfo: createDatasoucesFromSubscriptionsInfo |
||||
|
}; |
||||
|
|
||||
|
return service; |
||||
|
|
||||
|
function getEntityPromise(entityType, entityId, config) { |
||||
|
var promise; |
||||
|
switch (entityType) { |
||||
|
case types.entityType.device: |
||||
|
promise = deviceService.getDevice(entityId, true, config); |
||||
|
break; |
||||
|
case types.entityType.asset: |
||||
|
promise = assetService.getAsset(entityId, true, config); |
||||
|
break; |
||||
|
case types.entityType.tenant: |
||||
|
promise = tenantService.getTenant(entityId); |
||||
|
break; |
||||
|
case types.entityType.customer: |
||||
|
promise = customerService.getCustomer(entityId); |
||||
|
break; |
||||
|
case types.entityType.rule: |
||||
|
promise = ruleService.getRule(entityId); |
||||
|
break; |
||||
|
case types.entityType.plugin: |
||||
|
promise = pluginService.getPlugin(entityId); |
||||
|
break; |
||||
|
} |
||||
|
return promise; |
||||
|
} |
||||
|
|
||||
|
function getEntity(entityType, entityId, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var promise = getEntityPromise(entityType, entityId, config); |
||||
|
promise.then( |
||||
|
function success(result) { |
||||
|
deferred.resolve(result); |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.reject(); |
||||
|
} |
||||
|
); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getEntitiesByIdsPromise(fetchEntityFunction, entityIds) { |
||||
|
var tasks = []; |
||||
|
var deferred = $q.defer(); |
||||
|
for (var i=0;i<entityIds.length;i++) { |
||||
|
tasks.push(fetchEntityFunction(entityIds[i])); |
||||
|
} |
||||
|
$q.all(tasks).then( |
||||
|
function success(entities) { |
||||
|
if (entities) { |
||||
|
entities.sort(function (entity1, entity2) { |
||||
|
var id1 = entity1.id.id; |
||||
|
var id2 = entity2.id.id; |
||||
|
var index1 = entityIds.indexOf(id1); |
||||
|
var index2 = entityIds.indexOf(id2); |
||||
|
return index1 - index2; |
||||
|
}); |
||||
|
deferred.resolve(entities); |
||||
|
} else { |
||||
|
deferred.resolve([]); |
||||
|
} |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.reject(); |
||||
|
} |
||||
|
); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getEntitiesPromise(entityType, entityIds, config) { |
||||
|
var promise; |
||||
|
switch (entityType) { |
||||
|
case types.entityType.device: |
||||
|
promise = deviceService.getDevices(entityIds, config); |
||||
|
break; |
||||
|
case types.entityType.asset: |
||||
|
promise = assetService.getAssets(entityIds, config); |
||||
|
break; |
||||
|
case types.entityType.tenant: |
||||
|
promise = getEntitiesByIdsPromise(tenantService.getTenant, entityIds); |
||||
|
break; |
||||
|
case types.entityType.customer: |
||||
|
promise = getEntitiesByIdsPromise(customerService.getCustomer, entityIds); |
||||
|
break; |
||||
|
case types.entityType.rule: |
||||
|
promise = getEntitiesByIdsPromise(ruleService.getRule, entityIds); |
||||
|
break; |
||||
|
case types.entityType.plugin: |
||||
|
promise = getEntitiesByIdsPromise(pluginService.getPlugin, entityIds); |
||||
|
break; |
||||
|
} |
||||
|
return promise; |
||||
|
} |
||||
|
|
||||
|
function getEntities(entityType, entityIds, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var promise = getEntitiesPromise(entityType, entityIds, config); |
||||
|
promise.then( |
||||
|
function success(result) { |
||||
|
deferred.resolve(result); |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.reject(); |
||||
|
} |
||||
|
); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getEntitiesByPageLinkPromise(entityType, pageLink, config) { |
||||
|
var promise; |
||||
|
var user = userService.getCurrentUser(); |
||||
|
var customerId = user.customerId; |
||||
|
switch (entityType) { |
||||
|
case types.entityType.device: |
||||
|
if (user.authority === 'CUSTOMER_USER') { |
||||
|
promise = deviceService.getCustomerDevices(customerId, pageLink, false, config); |
||||
|
} else { |
||||
|
promise = deviceService.getTenantDevices(pageLink, false, config); |
||||
|
} |
||||
|
break; |
||||
|
case types.entityType.asset: |
||||
|
if (user.authority === 'CUSTOMER_USER') { |
||||
|
promise = assetService.getCustomerAssets(customerId, pageLink, false, config); |
||||
|
} else { |
||||
|
promise = assetService.getTenantAssets(pageLink, false, config); |
||||
|
} |
||||
|
break; |
||||
|
case types.entityType.tenant: |
||||
|
promise = tenantService.getTenants(pageLink); |
||||
|
break; |
||||
|
case types.entityType.customer: |
||||
|
promise = customerService.getCustomers(pageLink); |
||||
|
break; |
||||
|
case types.entityType.rule: |
||||
|
promise = ruleService.getAllRules(pageLink); |
||||
|
break; |
||||
|
case types.entityType.plugin: |
||||
|
promise = pluginService.getAllPlugins(pageLink); |
||||
|
break; |
||||
|
} |
||||
|
return promise; |
||||
|
} |
||||
|
|
||||
|
function getEntitiesByNameFilter(entityType, entityNameFilter, limit, config) { |
||||
|
var deferred = $q.defer(); |
||||
|
var pageLink = {limit: limit, textSearch: entityNameFilter}; |
||||
|
var promise = getEntitiesByPageLinkPromise(entityType, pageLink, config); |
||||
|
promise.then( |
||||
|
function success(result) { |
||||
|
if (result.data && result.data.length > 0) { |
||||
|
deferred.resolve(result.data); |
||||
|
} else { |
||||
|
deferred.resolve(null); |
||||
|
} |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.resolve(null); |
||||
|
} |
||||
|
); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function entityName(entityType, entity) { |
||||
|
var name = ''; |
||||
|
switch (entityType) { |
||||
|
case types.entityType.device: |
||||
|
case types.entityType.asset: |
||||
|
case types.entityType.rule: |
||||
|
case types.entityType.plugin: |
||||
|
name = entity.name; |
||||
|
break; |
||||
|
case types.entityType.tenant: |
||||
|
case types.entityType.customer: |
||||
|
name = entity.title; |
||||
|
break; |
||||
|
} |
||||
|
return name; |
||||
|
} |
||||
|
|
||||
|
function entityToEntityInfo(entityType, entity) { |
||||
|
return { name: entityName(entityType, entity), entityType: entityType, id: entity.id.id }; |
||||
|
} |
||||
|
|
||||
|
function entitiesToEntitiesInfo(entityType, entities) { |
||||
|
var entitiesInfo = []; |
||||
|
for (var d = 0; d < entities.length; d++) { |
||||
|
entitiesInfo.push(entityToEntityInfo(entityType, entities[d])); |
||||
|
} |
||||
|
return entitiesInfo; |
||||
|
} |
||||
|
|
||||
|
function processEntityAlias(index, aliasIds, entityAliases, resolution, deferred) { |
||||
|
if (index < aliasIds.length) { |
||||
|
var aliasId = aliasIds[index]; |
||||
|
var entityAlias = entityAliases[aliasId]; |
||||
|
var alias = entityAlias.alias; |
||||
|
var entityFilter = entityAlias.entityFilter; |
||||
|
if (entityFilter.useFilter) { |
||||
|
var entityNameFilter = entityFilter.entityNameFilter; |
||||
|
getEntitiesByNameFilter(entityAlias.entityType, entityNameFilter, 100).then( |
||||
|
function(entities) { |
||||
|
if (entities && entities != null) { |
||||
|
var resolvedAlias = {alias: alias, entityType: entityAlias.entityType, entityId: entities[0].id.id}; |
||||
|
resolution.aliasesInfo.entityAliases[aliasId] = resolvedAlias; |
||||
|
resolution.aliasesInfo.entityAliasesInfo[aliasId] = entitiesToEntitiesInfo(entityAlias.entityType, entities); |
||||
|
index++; |
||||
|
processEntityAlias(index, aliasIds, entityAliases, resolution, deferred); |
||||
|
} else { |
||||
|
if (!resolution.error) { |
||||
|
resolution.error = 'dashboard.invalid-aliases-config'; |
||||
|
} |
||||
|
index++; |
||||
|
processEntityAlias(index, aliasIds, entityAliases, resolution, deferred); |
||||
|
} |
||||
|
}); |
||||
|
} else { |
||||
|
var entityList = entityFilter.entityList; |
||||
|
getEntities(entityAlias.entityType, entityList).then( |
||||
|
function success(entities) { |
||||
|
if (entities && entities.length > 0) { |
||||
|
var resolvedAlias = {alias: alias, entityType: entityAlias.entityType, entityId: entities[0].id.id}; |
||||
|
resolution.aliasesInfo.entityAliases[aliasId] = resolvedAlias; |
||||
|
resolution.aliasesInfo.entityAliasesInfo[aliasId] = entitiesToEntitiesInfo(entityAlias.entityType, entities); |
||||
|
index++; |
||||
|
processEntityAlias(index, aliasIds, entityAliases, resolution, deferred); |
||||
|
} else { |
||||
|
if (!resolution.error) { |
||||
|
resolution.error = 'dashboard.invalid-aliases-config'; |
||||
|
} |
||||
|
index++; |
||||
|
processEntityAlias(index, aliasIds, entityAliases, resolution, deferred); |
||||
|
} |
||||
|
}, |
||||
|
function fail() { |
||||
|
if (!resolution.error) { |
||||
|
resolution.error = 'dashboard.invalid-aliases-config'; |
||||
|
} |
||||
|
index++; |
||||
|
processEntityAlias(index, aliasIds, entityAliases, resolution, deferred); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
} else { |
||||
|
deferred.resolve(resolution); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function processEntityAliases(entityAliases) { |
||||
|
var deferred = $q.defer(); |
||||
|
var resolution = { |
||||
|
aliasesInfo: { |
||||
|
entityAliases: {}, |
||||
|
entityAliasesInfo: {} |
||||
|
} |
||||
|
}; |
||||
|
var aliasIds = []; |
||||
|
if (entityAliases) { |
||||
|
for (var aliasId in entityAliases) { |
||||
|
aliasIds.push(aliasId); |
||||
|
} |
||||
|
} |
||||
|
processEntityAlias(0, aliasIds, entityAliases, resolution, deferred); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function getEntityKeys(entityType, entityId, query, type) { |
||||
|
var deferred = $q.defer(); |
||||
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/'; |
||||
|
if (type === types.dataKeyType.timeseries) { |
||||
|
url += 'timeseries'; |
||||
|
} else if (type === types.dataKeyType.attribute) { |
||||
|
url += 'attributes'; |
||||
|
} |
||||
|
$http.get(url, null).then(function success(response) { |
||||
|
var result = []; |
||||
|
if (response.data) { |
||||
|
if (query) { |
||||
|
var dataKeys = response.data; |
||||
|
var lowercaseQuery = angular.lowercase(query); |
||||
|
for (var i=0; i<dataKeys.length;i++) { |
||||
|
if (angular.lowercase(dataKeys[i]).indexOf(lowercaseQuery) === 0) { |
||||
|
result.push(dataKeys[i]); |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
result = response.data; |
||||
|
} |
||||
|
} |
||||
|
deferred.resolve(result); |
||||
|
}, function fail(response) { |
||||
|
deferred.reject(response.data); |
||||
|
}); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function checkEntityAlias(entityAlias) { |
||||
|
var deferred = $q.defer(); |
||||
|
var entityType = entityAlias.entityType; |
||||
|
var entityFilter = entityAlias.entityFilter; |
||||
|
var promise; |
||||
|
if (entityFilter.useFilter) { |
||||
|
var entityNameFilter = entityFilter.entityNameFilter; |
||||
|
promise = getEntitiesByNameFilter(entityType, entityNameFilter, 1); |
||||
|
} else { |
||||
|
var entityList = entityFilter.entityList; |
||||
|
promise = getEntities(entityType, entityList); |
||||
|
} |
||||
|
promise.then( |
||||
|
function success(entities) { |
||||
|
if (entities && entities.length > 0) { |
||||
|
deferred.resolve(true); |
||||
|
} else { |
||||
|
deferred.resolve(false); |
||||
|
} |
||||
|
}, |
||||
|
function fail() { |
||||
|
deferred.resolve(false); |
||||
|
} |
||||
|
); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function createDatasoucesFromSubscriptionsInfo(subscriptionsInfo) { |
||||
|
var deferred = $q.defer(); |
||||
|
var datasources = []; |
||||
|
processSubscriptionsInfo(0, subscriptionsInfo, datasources, deferred); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred) { |
||||
|
if (index < subscriptionsInfo.length) { |
||||
|
var subscriptionInfo = validateSubscriptionInfo(subscriptionsInfo[index]); |
||||
|
if (subscriptionInfo.type === types.datasourceType.entity) { |
||||
|
if (subscriptionInfo.entityId) { |
||||
|
getEntity(subscriptionInfo.entityType, subscriptionInfo.entityId, {ignoreLoading: true}).then( |
||||
|
function success(entity) { |
||||
|
createDatasourceFromSubscription(subscriptionInfo, datasources, entity); |
||||
|
index++; |
||||
|
processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred); |
||||
|
}, |
||||
|
function fail() { |
||||
|
index++; |
||||
|
processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred); |
||||
|
} |
||||
|
); |
||||
|
} else if (subscriptionInfo.entityName || subscriptionInfo.entityNamePrefix |
||||
|
|| subscriptionInfo.entityIds) { |
||||
|
var promise; |
||||
|
if (subscriptionInfo.entityName) { |
||||
|
promise = getEntitiesByNameFilter(subscriptionInfo.entityType, subscriptionInfo.entityName, 1, {ignoreLoading: true}); |
||||
|
} else if (subscriptionInfo.entityNamePrefix) { |
||||
|
promise = getEntitiesByNameFilter(subscriptionInfo.entityType, subscriptionInfo.entityNamePrefix, 100, {ignoreLoading: true}); |
||||
|
} else if (subscriptionInfo.entityIds) { |
||||
|
promise = getEntities(subscriptionInfo.entityType, subscriptionInfo.entityIds, {ignoreLoading: true}); |
||||
|
} |
||||
|
promise.then( |
||||
|
function success(entities) { |
||||
|
if (entities && entities.length > 0) { |
||||
|
for (var i = 0; i < entities.length; i++) { |
||||
|
var entity = entities[i]; |
||||
|
createDatasourceFromSubscription(subscriptionInfo, datasources, entity); |
||||
|
} |
||||
|
} |
||||
|
index++; |
||||
|
processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred); |
||||
|
}, |
||||
|
function fail() { |
||||
|
index++; |
||||
|
processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred); |
||||
|
} |
||||
|
) |
||||
|
} else { |
||||
|
index++; |
||||
|
processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred); |
||||
|
} |
||||
|
} else if (subscriptionInfo.type === types.datasourceType.function) { |
||||
|
createDatasourceFromSubscription(subscriptionInfo, datasources); |
||||
|
index++; |
||||
|
processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred); |
||||
|
} |
||||
|
} else { |
||||
|
deferred.resolve(datasources); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function validateSubscriptionInfo(subscriptionInfo) { |
||||
|
if (subscriptionInfo.type === 'device') { |
||||
|
subscriptionInfo.type = types.datasourceType.entity; |
||||
|
subscriptionInfo.entityType = types.entityType.device; |
||||
|
if (subscriptionInfo.deviceId) { |
||||
|
subscriptionInfo.entityId = subscriptionInfo.deviceId; |
||||
|
} else if (subscriptionInfo.deviceName) { |
||||
|
subscriptionInfo.entityName = subscriptionInfo.deviceName; |
||||
|
} else if (subscriptionInfo.deviceNamePrefix) { |
||||
|
subscriptionInfo.entityNamePrefix = subscriptionInfo.deviceNamePrefix; |
||||
|
} else if (subscriptionInfo.deviceIds) { |
||||
|
subscriptionInfo.entityIds = subscriptionInfo.deviceIds; |
||||
|
} |
||||
|
} |
||||
|
return subscriptionInfo; |
||||
|
} |
||||
|
|
||||
|
function createDatasourceFromSubscription(subscriptionInfo, datasources, entity) { |
||||
|
var datasource; |
||||
|
if (subscriptionInfo.type === types.datasourceType.entity) { |
||||
|
datasource = { |
||||
|
type: subscriptionInfo.type, |
||||
|
entityName: entity.name ? entity.name : entity.title, |
||||
|
name: entity.name ? entity.name : entity.title, |
||||
|
entityType: subscriptionInfo.entityType, |
||||
|
entityId: entity.id.id, |
||||
|
dataKeys: [] |
||||
|
} |
||||
|
} else if (subscriptionInfo.type === types.datasourceType.function) { |
||||
|
datasource = { |
||||
|
type: subscriptionInfo.type, |
||||
|
name: subscriptionInfo.name || types.datasourceType.function, |
||||
|
dataKeys: [] |
||||
|
} |
||||
|
} |
||||
|
datasources.push(datasource); |
||||
|
if (subscriptionInfo.timeseries) { |
||||
|
createDatasourceKeys(subscriptionInfo.timeseries, types.dataKeyType.timeseries, datasource, datasources); |
||||
|
} |
||||
|
if (subscriptionInfo.attributes) { |
||||
|
createDatasourceKeys(subscriptionInfo.attributes, types.dataKeyType.attribute, datasource, datasources); |
||||
|
} |
||||
|
if (subscriptionInfo.functions) { |
||||
|
createDatasourceKeys(subscriptionInfo.functions, types.dataKeyType.function, datasource, datasources); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function createDatasourceKeys(keyInfos, type, datasource, datasources) { |
||||
|
for (var i=0;i<keyInfos.length;i++) { |
||||
|
var keyInfo = keyInfos[i]; |
||||
|
var dataKey = utils.createKey(keyInfo, type, datasources); |
||||
|
datasource.dataKeys.push(dataKey); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -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. |
||||
|
|
||||
|
--> |
||||
|
<md-dialog aria-label="{{ 'asset.add' | translate }}" tb-help="'assets'" help-container-id="help-container"> |
||||
|
<form name="theForm" ng-submit="vm.add()"> |
||||
|
<md-toolbar> |
||||
|
<div class="md-toolbar-tools"> |
||||
|
<h2 translate>asset.add</h2> |
||||
|
<span flex></span> |
||||
|
<div id="help-container"></div> |
||||
|
<md-button class="md-icon-button" ng-click="vm.cancel()"> |
||||
|
<ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> |
||||
|
</md-button> |
||||
|
</div> |
||||
|
</md-toolbar> |
||||
|
<md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear> |
||||
|
<span style="min-height: 5px;" flex="" ng-show="!loading"></span> |
||||
|
<md-dialog-content> |
||||
|
<div class="md-dialog-content"> |
||||
|
<tb-asset asset="vm.item" is-edit="true" the-form="theForm"></tb-asset> |
||||
|
</div> |
||||
|
</md-dialog-content> |
||||
|
<md-dialog-actions layout="row"> |
||||
|
<span flex></span> |
||||
|
<md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> |
||||
|
{{ 'action.add' | translate }} |
||||
|
</md-button> |
||||
|
<md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> |
||||
|
</md-dialog-actions> |
||||
|
</form> |
||||
|
</md-dialog> |
||||
@ -0,0 +1,123 @@ |
|||||
|
/* |
||||
|
* 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. |
||||
|
*/ |
||||
|
/*@ngInject*/ |
||||
|
export default function AddAssetsToCustomerController(assetService, $mdDialog, $q, customerId, assets) { |
||||
|
|
||||
|
var vm = this; |
||||
|
|
||||
|
vm.assets = assets; |
||||
|
vm.searchText = ''; |
||||
|
|
||||
|
vm.assign = assign; |
||||
|
vm.cancel = cancel; |
||||
|
vm.hasData = hasData; |
||||
|
vm.noData = noData; |
||||
|
vm.searchAssetTextUpdated = searchAssetTextUpdated; |
||||
|
vm.toggleAssetSelection = toggleAssetSelection; |
||||
|
|
||||
|
vm.theAssets = { |
||||
|
getItemAtIndex: function (index) { |
||||
|
if (index > vm.assets.data.length) { |
||||
|
vm.theAssets.fetchMoreItems_(index); |
||||
|
return null; |
||||
|
} |
||||
|
var item = vm.assets.data[index]; |
||||
|
if (item) { |
||||
|
item.indexNumber = index + 1; |
||||
|
} |
||||
|
return item; |
||||
|
}, |
||||
|
|
||||
|
getLength: function () { |
||||
|
if (vm.assets.hasNext) { |
||||
|
return vm.assets.data.length + vm.assets.nextPageLink.limit; |
||||
|
} else { |
||||
|
return vm.assets.data.length; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
fetchMoreItems_: function () { |
||||
|
if (vm.assets.hasNext && !vm.assets.pending) { |
||||
|
vm.assets.pending = true; |
||||
|
assetService.getTenantAssets(vm.assets.nextPageLink, false).then( |
||||
|
function success(assets) { |
||||
|
vm.assets.data = vm.assets.data.concat(assets.data); |
||||
|
vm.assets.nextPageLink = assets.nextPageLink; |
||||
|
vm.assets.hasNext = assets.hasNext; |
||||
|
if (vm.assets.hasNext) { |
||||
|
vm.assets.nextPageLink.limit = vm.assets.pageSize; |
||||
|
} |
||||
|
vm.assets.pending = false; |
||||
|
}, |
||||
|
function fail() { |
||||
|
vm.assets.hasNext = false; |
||||
|
vm.assets.pending = false; |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
function cancel () { |
||||
|
$mdDialog.cancel(); |
||||
|
} |
||||
|
|
||||
|
function assign() { |
||||
|
var tasks = []; |
||||
|
for (var assetId in vm.assets.selections) { |
||||
|
tasks.push(assetService.assignAssetToCustomer(customerId, assetId)); |
||||
|
} |
||||
|
$q.all(tasks).then(function () { |
||||
|
$mdDialog.hide(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function noData() { |
||||
|
return vm.assets.data.length == 0 && !vm.assets.hasNext; |
||||
|
} |
||||
|
|
||||
|
function hasData() { |
||||
|
return vm.assets.data.length > 0; |
||||
|
} |
||||
|
|
||||
|
function toggleAssetSelection($event, asset) { |
||||
|
$event.stopPropagation(); |
||||
|
var selected = angular.isDefined(asset.selected) && asset.selected; |
||||
|
asset.selected = !selected; |
||||
|
if (asset.selected) { |
||||
|
vm.assets.selections[asset.id.id] = true; |
||||
|
vm.assets.selectedCount++; |
||||
|
} else { |
||||
|
delete vm.assets.selections[asset.id.id]; |
||||
|
vm.assets.selectedCount--; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function searchAssetTextUpdated() { |
||||
|
vm.assets = { |
||||
|
pageSize: vm.assets.pageSize, |
||||
|
data: [], |
||||
|
nextPageLink: { |
||||
|
limit: vm.assets.pageSize, |
||||
|
textSearch: vm.searchText |
||||
|
}, |
||||
|
selections: {}, |
||||
|
selectedCount: 0, |
||||
|
hasNext: true, |
||||
|
pending: false |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue