class FlowRefresherTask implements Runnable {

    void refreshAgentClass(final String agentClassName, final AtomicInteger refreshedCount)
            throws FlowMapperException, IOException, FlowRetrievalException, SerializerException, FlowTransformException {

        // Determine the uri from NiFi Registry that maps to this class
        final Optional<FlowUri> optionalFlowUri = flowMapper.getFlowMapping(agentClassName);
        if (!optionalFlowUri.isPresent()) {
            LOGGER.debug("No flow mapping present for '{}'", new Object[] {agentClassName});
            return;
        }

        final FlowUri flowUri = optionalFlowUri.get();
        LOGGER.debug("Found flow {} mapped to '{}'", new Object[]{flowUri.getFlowId(), agentClassName});

        // Get the latest version available for the uri we got above
        final VersionedFlowSnapshot latestFlow = flowRetrievalService.getLatestFlow(flowUri);
        if (latestFlow == null) {
            LOGGER.debug("No flow versions exist for '{}'", new Object[] {agentClassName});
            return;
        }

        // Query the database to see if we anything currently mapped for the given agent class
        final Optional<FlowMappingEntity> optionalFlowMapping = flowMappingRepository.findById(agentClassName);
        if (optionalFlowMapping.isPresent()) {
            final FlowMappingEntity existingFlowMapping = optionalFlowMapping.get();

            final String existingRegistryUrl = existingFlowMapping.getFlowEntity().getRegistryUrl();
            final String existingBucketId = existingFlowMapping.getFlowEntity().getRegistryBucketId();
            final String existingFlowId = existingFlowMapping.getFlowEntity().getRegistryFlowId();

            if (flowUri.getRegistryUrl().equals(existingRegistryUrl)
                    && flowUri.getBucketId().equals(existingBucketId)
                    && flowUri.getFlowId().equals(existingFlowId)) {

                final FlowEntity existingFlow = existingFlowMapping.getFlowEntity();
                if (latestFlow.getSnapshotMetadata().getVersion() > existingFlow.getRegistryFlowVersion()) {
                    updateFlowMapping(existingFlowMapping, flowUri, latestFlow);
                    refreshedCount.incrementAndGet();
                } else {
                    LOGGER.debug("'{}' already mapped to latest version, nothing to do...", new Object[]{agentClassName});
                }

            } else {
                // Existing mapping doesn't match the flow uri we have so we have to update the flow mapping to point
                // to a new flow, this could happen if the C2 server is restarted to point at a different NiFi registry
                updateFlowMapping(existingFlowMapping, flowUri, latestFlow);
                refreshedCount.incrementAndGet();
            }

        } else {
            // No mapping present yet so we need to create a new one
            createNewFlowMapping(agentClassName, flowUri, latestFlow);
            refreshedCount.incrementAndGet();
        }
    }

    @Autowired public  FlowRefresherTask(
            final AgentClassRepository agentClassRepository,
            final FlowMapper flowMapper,
            final FlowRetrievalService flowRetrievalService,
            final FlowTransformService<ConfigSchema> flowTransformService,
            final Serializer<ConfigSchema> configSchemaSerializer,
            final FlowRepository flowRepository,
            final FlowMappingRepository flowMappingRepository,
            final TransactionTemplate transactionTemplate);

}