docs: public static TopicWrapper cloneTopic(final DataProviderFactory providerFactory, final ITopicNode specTopic,
              final ServerEntitiesWrapper serverEntities) {
          final TopicProvider topicProvider = providerFactory.getProvider(TopicProvider.class);
          final TopicSourceURLProvider topicSourceUrlProvider = providerFactory.getProvider(TopicSourceURLProvider.class);
          final TagProvider tagProvider = providerFactory.getProvider(TagProvider.class);
          final PropertyTagProvider propertyTagProvider = providerFactory.getProvider(PropertyTagProvider.class);
  
          // Get the existing topic from the database
          int clonedId = Integer.parseInt(specTopic.getId().substring(1));
          final TopicWrapper originalTopic = topicProvider.getTopic(clonedId, null);
          final TopicWrapper cloneTopic = topicProvider.newTopic();
  
          LOG.debug("Cloning existing topic " + originalTopic.getId());
  
          // Set the ID to null so a new ID will be created
          cloneTopic.setId(null);
          // Set-up the basic parameters
          cloneTopic.setTitle(originalTopic.getTitle());
          cloneTopic.setDescription(originalTopic.getDescription());
          cloneTopic.setXml(originalTopic.getXml());
          cloneTopic.setXmlFormat(originalTopic.getXmlFormat());
          cloneTopic.setLocale(originalTopic.getLocale());
  
          // Go through each collection and add the original topics data
          if (originalTopic.getIncomingRelationships() != null && !originalTopic.getIncomingRelationships().isEmpty()) {
              final CollectionWrapper<TopicWrapper> cloneIncomingTopics = topicProvider.newTopicCollection();
              for (final TopicWrapper incomingRelationship : originalTopic.getIncomingRelationships().getItems()) {
                  cloneIncomingTopics.addNewItem(incomingRelationship);
              }
              cloneTopic.setIncomingRelationships(cloneIncomingTopics);
          }
  
          if (originalTopic.getOutgoingRelationships() != null && !originalTopic.getOutgoingRelationships().isEmpty()) {
              final CollectionWrapper<TopicWrapper> cloneOutgoingTopics = topicProvider.newTopicCollection();
              for (final TopicWrapper outgoingRelationship : originalTopic.getOutgoingRelationships().getItems()) {
                  cloneOutgoingTopics.addNewItem(outgoingRelationship);
              }
              cloneTopic.setOutgoingRelationships(cloneOutgoingTopics);
          }
  
          // SOURCE URLS
          if (originalTopic.getSourceURLs() != null && !originalTopic.getSourceURLs().isEmpty()) {
              final UpdateableCollectionWrapper<TopicSourceURLWrapper> cloneSourceUrls = topicSourceUrlProvider.newTopicSourceURLCollection(
                      cloneTopic);
              for (final TopicSourceURLWrapper sourceUrl : originalTopic.getSourceURLs().getItems()) {
                  final TopicSourceURLWrapper cloneSourceUrl = cloneTopicSourceUrl(topicSourceUrlProvider, sourceUrl, cloneTopic);
                  cloneSourceUrls.addNewItem(cloneSourceUrl);
              }
              cloneTopic.setSourceURLs(cloneSourceUrls);
          }
  
          // TAGS
          if (originalTopic.getTags() != null && !originalTopic.getTags().isEmpty()) {
              final CollectionWrapper<TagWrapper> newTags = tagProvider.newTagCollection();
              final List<TagWrapper> tags = originalTopic.getTags().getItems();
              for (final TagWrapper tag : tags) {
                  // Remove the old writer tag as it will get replaced
                  if (!tag.containedInCategory(serverEntities.getWriterCategoryId())) {
                      newTags.addNewItem(tag);
                  }
              }
  
              // Set the tags if any tags exist
              if (!newTags.isEmpty()) {
                  cloneTopic.setTags(newTags);
              }
          }
  
          // Copy all the existing property tags
          final UpdateableCollectionWrapper<PropertyTagInTopicWrapper> newProperties = propertyTagProvider.newPropertyTagInTopicCollection(
                  cloneTopic);
          final List<PropertyTagInTopicWrapper> propertyItems = originalTopic.getProperties().getItems();
          for (final PropertyTagInTopicWrapper property : propertyItems) {
              final PropertyTagInTopicWrapper clonedProperty = cloneTopicProperty(cloneTopic, propertyTagProvider, property);
              // Ignore the CSP and Added By Property ID as we will add a new one later
              if (!(property.getId().equals(serverEntities.getCspIdPropertyTagId()) || property.getId().equals(serverEntities.getAddedByPropertyTagId()))) {
                  newProperties.addNewItem(clonedProperty);
              }
          }
  
          // Add the added by property tag
          final String assignedWriter = specTopic.getAssignedWriter(true);
          if (assignedWriter != null) {
              final PropertyTagWrapper addedByPropertyTag = propertyTagProvider.getPropertyTag(serverEntities.getAddedByPropertyTagId());
              final PropertyTagInTopicWrapper addedByProperty = propertyTagProvider.newPropertyTagInTopic(addedByPropertyTag, cloneTopic);
              addedByProperty.setValue(assignedWriter);
              newProperties.addNewItem(addedByProperty);
          }
  
          if (!newProperties.isEmpty()) {
              cloneTopic.setProperties(newProperties);
          }
  
          return cloneTopic;
      }