PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/plugin/src/main/java/net/customware/confluence/plugin/toc/TOCMacro.java

https://bitbucket.org/atlassian/confluence-toc-plugin
Java | 179 lines | 115 code | 23 blank | 41 comment | 3 complexity | b9657fe521a8a7f044ba3d809c7f7bcc MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*
  2. * Copyright (c) 2007, CustomWare Asia Pacific
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright notice,
  9. * this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * * Neither the name of "CustomWare Asia Pacific" nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. * POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. package net.customware.confluence.plugin.toc;
  30. import com.atlassian.confluence.content.render.xhtml.ConversionContext;
  31. import com.atlassian.confluence.content.render.xhtml.HtmlToXmlConverter;
  32. import com.atlassian.confluence.content.render.xhtml.Streamable;
  33. import com.atlassian.confluence.content.render.xhtml.Streamables;
  34. import com.atlassian.confluence.core.ContentEntityObject;
  35. import com.atlassian.confluence.languages.LocaleManager;
  36. import com.atlassian.confluence.macro.MacroExecutionException;
  37. import com.atlassian.confluence.macro.StreamableMacro;
  38. import com.atlassian.confluence.renderer.template.TemplateRenderer;
  39. import com.atlassian.confluence.setup.settings.SettingsManager;
  40. import com.atlassian.confluence.util.i18n.I18NBeanFactory;
  41. import com.atlassian.confluence.xhtml.api.XhtmlContent;
  42. import com.atlassian.event.api.EventPublisher;
  43. import com.atlassian.renderer.v2.RenderMode;
  44. import com.atlassian.webresource.api.assembler.PageBuilderService;
  45. import org.slf4j.Logger;
  46. import org.slf4j.LoggerFactory;
  47. import java.io.IOException;
  48. import java.io.Writer;
  49. import java.util.Map;
  50. import static com.atlassian.confluence.macro.Macro.BodyType.NONE;
  51. import static com.atlassian.renderer.v2.RenderMode.NO_RENDER;
  52. import static org.apache.commons.lang3.StringUtils.EMPTY;
  53. /**
  54. * Creates a table of contents based on the contents of the page.
  55. * For normal page display, this delegates to a javascript-based implementation
  56. */
  57. public class TOCMacro extends AbstractTOCMacro implements StreamableMacro {
  58. private static final Logger log = LoggerFactory.getLogger(TOCMacro.class);
  59. private static final String SOY_TEMPLATES_MODULE_NAME = PLUGIN_KEY + ":server-soy-templates";
  60. private static final String CLIENT_IMPL_CONTAINER_TEMPLATE = "Confluence.Plugins.TableOfContents.Server.clientSideTocContainer.soy";
  61. private final XhtmlContent xhtmlContent;
  62. private final PageBuilderService pageBuilderService;
  63. private final TemplateRenderer templateRenderer;
  64. private final EventPublisher eventPublisher;
  65. public TOCMacro(
  66. StaxDocumentOutlineCreator staxDocumentOutlineCreator,
  67. XhtmlContent xhtmlContent,
  68. HtmlToXmlConverter htmlToXmlConverter,
  69. SettingsManager settingsManager,
  70. LocaleManager localeManager,
  71. I18NBeanFactory i18nBeanFactory,
  72. PageBuilderService pageBuilderService,
  73. TemplateRenderer templateRenderer, final EventPublisher eventPublisher) {
  74. super(staxDocumentOutlineCreator, htmlToXmlConverter,
  75. settingsManager, localeManager, i18nBeanFactory, pageBuilderService);
  76. this.xhtmlContent = xhtmlContent;
  77. this.pageBuilderService = pageBuilderService;
  78. this.templateRenderer = templateRenderer;
  79. this.eventPublisher = eventPublisher;
  80. }
  81. /**
  82. * The main entry point to the macro. Decides which implementation (client or server) to go with.
  83. */
  84. @Override
  85. public Streamable executeToStream(final Map<String, String> macroParameters, final Streamable macroBody, final ConversionContext context)
  86. throws MacroExecutionException {
  87. final TocMacroImplementationType implementationType = TocMacroImplementationType.selectImplementation(context);
  88. eventPublisher.publish(implementationType.createEvent());
  89. switch (implementationType) {
  90. case SERVER:
  91. return renderServerSideImplementation(macroParameters, macroBody, context);
  92. case CLIENT:
  93. return renderClientSideImplementation(macroParameters);
  94. default:
  95. throw new MacroExecutionException("Failed to select TOCMacro implementation");
  96. }
  97. }
  98. private Streamable renderServerSideImplementation(final Map<String, String> macroParameters, final Streamable macroBody, final ConversionContext context)
  99. throws MacroExecutionException {
  100. return Streamables.from(execute(macroParameters, Streamables.writeToString(macroBody), context));
  101. }
  102. private Streamable renderClientSideImplementation(final Map<String, String> macroParameters) {
  103. pageBuilderService.assembler().resources().requireContext(CLIENT_IMPL_WEBRESOURCE_CONTEXT);
  104. final Map<String, Object> templateModel = ClientTocMacroTemplateModel.buildTemplateModel(macroParameters);
  105. return new Streamable() {
  106. @Override
  107. public void writeTo(final Writer writer) throws IOException {
  108. templateRenderer.renderTo(writer, SOY_TEMPLATES_MODULE_NAME, CLIENT_IMPL_CONTAINER_TEMPLATE, templateModel);
  109. }
  110. };
  111. }
  112. /**
  113. * This macro operates on the body of the content entity (e.g. the page) on which the macro is a part of. This
  114. * method fetches the content body (which should be in XHTML storage-format), renders that to view-format, then
  115. * returns that to be used as the basis of the TOC generation.
  116. */
  117. @Override
  118. protected String getContent(final Map<String, String> parameters, final String body, final ConversionContext conversionContext) {
  119. final ContentEntityObject contentEntity = conversionContext.getEntity();
  120. if (contentEntity == null) {
  121. log.warn("There was an error converting the preview content to view - content entity object was null.");
  122. return "";
  123. }
  124. try {
  125. return xhtmlContent.convertStorageToView(contentEntity.getBodyAsString(), conversionContext);
  126. } catch (Exception ex) {
  127. log.warn("There was an error converting the content for id " + contentEntity.getId() + " to storage format.", ex);
  128. return "";
  129. }
  130. }
  131. @Override
  132. protected String createOutput(Map<String, String> parameters, String body, String toc) {
  133. // Just return the toc as-is.
  134. return toc;
  135. }
  136. @Override
  137. protected String getDefaultType() {
  138. return LIST_TYPE;
  139. }
  140. @Override
  141. protected String getUnprintableHtml(final String body) {
  142. return EMPTY;
  143. }
  144. @Override
  145. public boolean hasBody() {
  146. return false;
  147. }
  148. @Override
  149. public BodyType getBodyType() {
  150. return NONE;
  151. }
  152. @Override
  153. public RenderMode getBodyRenderMode() {
  154. return NO_RENDER;
  155. }
  156. }