docs: @SuppressWarnings("unchecked")
      private <T extends BaseTopicWrapper<T>> void doSpecTopicSecondPass(final BuildData buildData,
              final Map<SpecTopic, Set<String>> usedIdAttributes) throws BuildProcessingException {
          log.info("Doing " + buildData.getBuildLocale() + " Spec Topic Pass");
          final List<ITopicNode> topicNodes = buildData.getBuildDatabase().getAllTopicNodes();
  
          log.info("\tProcessing " + topicNodes.size() + " Spec Topics");
  
          final int showPercent = 10;
          final float total = topicNodes.size();
          float current = 0;
          int lastPercent = 0;
  
          final DocBookXMLPreProcessor xmlPreProcessor = buildData.getXMLPreProcessor();
  
          for (final ITopicNode topicNode : topicNodes) {
              // Check if the app should be shutdown
              if (isShuttingDown.get()) {
                  return;
              }
  
              if (log.isDebugEnabled()) log.debug("\tProcessing SpecTopic " + topicNode.getId() + (topicNode.getRevision() != null ? (", " +
                      "Revision " + topicNode.getRevision()) : ""));
  
              ++current;
              final int percent = Math.round(current / total * 100);
              if (percent - lastPercent >= showPercent) {
                  lastPercent = percent;
                  log.info("\tProcessing Pass " + percent + "% Done");
              }
  
              final BaseTopicWrapper<?> topic = topicNode.getTopic();
              final Document doc = topicNode.getXMLDocument();
  
              assert doc != null;
              assert topic != null;
  
              if (doc != null) {
                  final boolean valid = processSpecTopicInjections(buildData, topicNode, xmlPreProcessor);
  
                  // Check if the app should be shutdown
                  if (isShuttingDown.get()) {
                      return;
                  }
  
                  if (!valid) {
                      final String xmlStringInCDATA = DocBookBuildUtilities.convertDocumentToCDATAFormattedString(doc,
                              getXMLFormatProperties());
                      buildData.getErrorDatabase().addError(topic,
                              BuilderConstants.ERROR_INVALID_INJECTIONS + " The processed XML is <programlisting>" + xmlStringInCDATA +
                                      "</programlisting>");
  
                      DocBookBuildUtilities.setTopicNodeXMLForError(buildData, topicNode, getErrorInvalidInjectionTopicTemplate().getValue());
                  } else {
                      // Check for any possible invalid injection references
                      final List<InjectionError> injectionErrors = XMLUtilities.checkForInvalidInjections(doc);
                      if (!injectionErrors.isEmpty()) {
                          for (final InjectionError injectionError : injectionErrors) {
                              final List<String> injectionErrorMsgs = new ArrayList<String>();
                              for (final String msg : injectionError.getMessages()) {
                                  injectionErrorMsgs.add(DocBookUtilities.buildListItem(msg));
                              }
  
                              final String errorMsg = "\"" + injectionError.getInjection().trim() + "\" " + BuilderConstants
                                      .WARNING_POSSIBLE_INVALID_INJECTIONS + DocBookUtilities.wrapListItems(
                                      injectionErrorMsgs);
                              buildData.getErrorDatabase().addWarning(topic, ErrorType.POSSIBLE_INVALID_INJECTION, errorMsg);
                          }
                      }
                  }
  
                  // Ensure that all of the id attributes are valid by setting any duplicates with a post fixed number.
                  DocBookBuildUtilities.setUniqueIds(buildData, topicNode, topicNode.getXMLDocument().getDocumentElement(),
                          topicNode.getXMLDocument(), usedIdAttributes);
  
                  // Make sure the XML is valid docbook after the standard processing has been done
                  if (validateTopicXML(buildData, topicNode, doc) && topicNode instanceof SpecTopic) {
                      // Add the editor/report a bug links (these should always be valid)
                      xmlPreProcessor.processTopicAdditionalInfo(buildData, (SpecTopic) topicNode, doc);
                  } else {
                      // Re-run the unique id pass, as the topic would have been replaced by an error template
                      DocBookBuildUtilities.setUniqueIds(buildData, topicNode, topicNode.getXMLDocument().getDocumentElement(),
                              topicNode.getXMLDocument(), usedIdAttributes);
                  }
              }
          }
      }