13 changed files with 383 additions and 202 deletions
@ -0,0 +1,144 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.entity.queue; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.SneakyThrows; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.id.QueueId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|||
import org.thingsboard.server.dao.queue.QueueService; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueClusterService; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
@Slf4j |
|||
@Service |
|||
@TbCoreComponent |
|||
@AllArgsConstructor |
|||
public class DefaultTbQueueService implements TbQueueService { |
|||
private final QueueService queueService; |
|||
private final TbQueueClusterService queueClusterService; |
|||
private final TbQueueAdmin tbQueueAdmin; |
|||
|
|||
@Override |
|||
public Queue saveQueue(Queue queue) { |
|||
boolean create = queue.getId() == null; |
|||
Queue oldQueue; |
|||
|
|||
if (create) { |
|||
oldQueue = null; |
|||
} else { |
|||
oldQueue = queueService.findQueueById(queue.getTenantId(), queue.getId()); |
|||
} |
|||
|
|||
//TODO: add checkNotNull
|
|||
Queue savedQueue = queueService.saveQueue(queue); |
|||
|
|||
if (create) { |
|||
onQueueCreated(savedQueue); |
|||
} else { |
|||
onQueueUpdated(savedQueue, oldQueue); |
|||
} |
|||
|
|||
return savedQueue; |
|||
} |
|||
|
|||
@Override |
|||
public void deleteQueue(TenantId tenantId, QueueId queueId) { |
|||
Queue queue = queueService.findQueueById(tenantId, queueId); |
|||
queueService.deleteQueue(tenantId, queueId); |
|||
onQueueDeleted(tenantId, queue); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteQueueByQueueName(TenantId tenantId, String queueName) { |
|||
Queue queue = queueService.findQueueByTenantIdAndNameInternal(tenantId, queueName); |
|||
queueService.deleteQueue(tenantId, queue.getId()); |
|||
onQueueDeleted(tenantId, queue); |
|||
} |
|||
|
|||
private void onQueueCreated(Queue queue) { |
|||
if (tbQueueAdmin != null) { |
|||
for (int i = 0; i < queue.getPartitions(); i++) { |
|||
tbQueueAdmin.createTopicIfNotExists( |
|||
new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); |
|||
} |
|||
} |
|||
|
|||
if (queueClusterService != null) { |
|||
queueClusterService.onQueueChange(queue); |
|||
} |
|||
} |
|||
|
|||
private void onQueueUpdated(Queue queue, Queue oldQueue) { |
|||
int oldPartitions = oldQueue.getPartitions(); |
|||
int currentPartitions = queue.getPartitions(); |
|||
|
|||
if (currentPartitions != oldPartitions && tbQueueAdmin != null) { |
|||
if (currentPartitions > oldPartitions) { |
|||
log.info("Added [{}] new partitions to [{}] queue", currentPartitions - oldPartitions, queue.getName()); |
|||
for (int i = oldPartitions; i < currentPartitions; i++) { |
|||
tbQueueAdmin.createTopicIfNotExists( |
|||
new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); |
|||
} |
|||
if (queueClusterService != null) { |
|||
queueClusterService.onQueueChange(queue); |
|||
} |
|||
} else { |
|||
log.info("Removed [{}] partitions from [{}] queue", oldPartitions - currentPartitions, queue.getName()); |
|||
if (queueClusterService != null) { |
|||
queueClusterService.onQueueChange(queue); |
|||
} |
|||
await(); |
|||
for (int i = currentPartitions; i < oldPartitions; i++) { |
|||
tbQueueAdmin.deleteTopic( |
|||
new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); |
|||
} |
|||
} |
|||
} else if (!oldQueue.equals(queue) && queueClusterService != null) { |
|||
queueClusterService.onQueueChange(queue); |
|||
} |
|||
} |
|||
|
|||
private void onQueueDeleted(TenantId tenantId, Queue queue) { |
|||
if (queueClusterService != null) { |
|||
queueClusterService.onQueueDelete(queue); |
|||
await(); |
|||
} |
|||
// queueStatsService.deleteQueueStatsByQueueId(tenantId, queueId);
|
|||
if (tbQueueAdmin != null) { |
|||
for (int i = 0; i < queue.getPartitions(); i++) { |
|||
String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(); |
|||
log.debug("Deleting queue [{}]", fullTopicName); |
|||
try { |
|||
tbQueueAdmin.deleteTopic(fullTopicName); |
|||
} catch (Exception e) { |
|||
log.error("Failed to delete queue [{}]", fullTopicName); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@SneakyThrows |
|||
private void await() { |
|||
Thread.sleep(3000); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.entity.queue; |
|||
|
|||
import org.thingsboard.server.common.data.id.QueueId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
|
|||
public interface TbQueueService { |
|||
|
|||
Queue saveQueue(Queue queue); |
|||
|
|||
void deleteQueue(TenantId tenantId, QueueId queueId); |
|||
|
|||
void deleteQueueByQueueName(TenantId tenantId, String queueName); |
|||
} |
|||
@ -0,0 +1,135 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.entity.tenant; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.Tenant; |
|||
import org.thingsboard.server.common.data.TenantProfile; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; |
|||
import org.thingsboard.server.dao.queue.QueueService; |
|||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
|||
import org.thingsboard.server.dao.tenant.TenantProfileService; |
|||
import org.thingsboard.server.dao.tenant.TenantService; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.entity.queue.TbQueueService; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Slf4j |
|||
@Service |
|||
@TbCoreComponent |
|||
@AllArgsConstructor |
|||
public class DefaultTbTenantService implements TbTenantService { |
|||
|
|||
private final TenantService tenantService; |
|||
private final TbQueueService tbQueueService; |
|||
private final QueueService queueService; |
|||
private final TenantProfileService tenantProfileService; |
|||
private final TbTenantProfileCache tenantProfileCache; |
|||
|
|||
@Override |
|||
public Tenant saveTenant(Tenant tenant) { |
|||
boolean updated = tenant.getId() != null; |
|||
Tenant oldTenant = updated ? tenantService.findTenantById(tenant.getId()) : null; |
|||
List<Queue> queues; |
|||
if (updated) { |
|||
|
|||
} |
|||
|
|||
Tenant savedTenant = tenantService.saveTenant(tenant); |
|||
tenantProfileCache.evict(tenant.getId()); |
|||
updateQueuesForTenant(oldTenant, savedTenant); |
|||
return savedTenant; |
|||
} |
|||
|
|||
public void updateQueuesForTenant(Tenant oldTenant, Tenant newTenant) { |
|||
TenantProfile oldTenantProfile = oldTenant != null ? tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, oldTenant.getTenantProfileId()) : null; |
|||
TenantProfile newTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, newTenant.getTenantProfileId()); |
|||
|
|||
TenantId tenantId = newTenant.getId(); |
|||
|
|||
boolean oldIsolated = oldTenantProfile != null && oldTenantProfile.isIsolatedTbRuleEngine(); |
|||
boolean newIsolated = newTenantProfile.isIsolatedTbRuleEngine(); |
|||
|
|||
if (!oldIsolated && !newIsolated) { |
|||
return; |
|||
} |
|||
|
|||
if (newTenantProfile.equals(oldTenantProfile)) { |
|||
return; |
|||
} |
|||
|
|||
Map<String, TenantProfileQueueConfiguration> oldQueues; |
|||
Map<String, TenantProfileQueueConfiguration> newQueues; |
|||
|
|||
if (oldIsolated) { |
|||
oldQueues = oldTenantProfile.getProfileData().getQueueConfiguration().stream() |
|||
.collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); |
|||
} else { |
|||
oldQueues = Collections.emptyMap(); |
|||
} |
|||
|
|||
if (newIsolated) { |
|||
newQueues = newTenantProfile.getProfileData().getQueueConfiguration().stream() |
|||
.collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); |
|||
} else { |
|||
newQueues = Collections.emptyMap(); |
|||
} |
|||
|
|||
List<String> toRemove = new ArrayList<>(); |
|||
List<String> toCreate = new ArrayList<>(); |
|||
List<String> toUpdate = new ArrayList<>(); |
|||
|
|||
for (String oldQueue : oldQueues.keySet()) { |
|||
if (!newQueues.containsKey(oldQueue)) { |
|||
toRemove.add(oldQueue); |
|||
} |
|||
} |
|||
|
|||
for (String newQueue : newQueues.keySet()) { |
|||
if (oldQueues.containsKey(newQueue)) { |
|||
toUpdate.add(newQueue); |
|||
} else { |
|||
toCreate.add(newQueue); |
|||
} |
|||
} |
|||
|
|||
toRemove.forEach(q -> tbQueueService.deleteQueueByQueueName(tenantId, q)); |
|||
|
|||
toCreate.forEach(key -> tbQueueService.saveQueue(new Queue(tenantId, newQueues.get(key)))); |
|||
|
|||
toUpdate.forEach(key -> { |
|||
Queue queueToUpdate = new Queue(tenantId, newQueues.get(key)); |
|||
Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, key); |
|||
queueToUpdate.setId(foundQueue.getId()); |
|||
queueToUpdate.setCreatedTime(foundQueue.getCreatedTime()); |
|||
|
|||
if (queueToUpdate.equals(foundQueue)) { |
|||
//Queue not changed
|
|||
} else { |
|||
tbQueueService.saveQueue(queueToUpdate); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.service.entity.tenant; |
|||
|
|||
import org.thingsboard.server.common.data.Tenant; |
|||
|
|||
public interface TbTenantService { |
|||
|
|||
Tenant saveTenant(Tenant tenant); |
|||
} |
|||
Loading…
Reference in new issue