PageRenderTime 37ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/org/andya/confluence/plugins/metadata/MetadataTableMacro.java

https://bitbucket.org/jwalton/metadata-confluence-plugin
Java | 242 lines | 173 code | 20 blank | 49 comment | 43 complexity | c92627d139541837027c31e345301aa9 MD5 | raw file
  1. /*
  2. * Copyright (c) 2006, 2007 Andy Armstrong, Kelsey Grant and other contributors.
  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 notice,
  11. * this list of conditions and the following disclaimer in the documentation
  12. * and/or other materials provided with the distribution.
  13. * * The names of contributors may not
  14. * be used to endorse or promote products derived from this software without
  15. * specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  21. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  24. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. package org.andya.confluence.plugins.metadata;
  29. import com.atlassian.renderer.RenderContext;
  30. import com.atlassian.renderer.v2.RenderMode;
  31. import com.atlassian.renderer.v2.macro.MacroException;
  32. import java.util.ArrayList;
  33. import java.util.Collections;
  34. import java.util.List;
  35. import java.util.Map;
  36. import java.util.HashMap;
  37. import java.math.BigDecimal;
  38. import org.andya.confluence.utils.MacroUtils;
  39. import org.andya.confluence.plugins.metadata.model.MetadataContent;
  40. import org.andya.confluence.plugins.metadata.model.MetadataValue;
  41. /**
  42. * Macro allowing tablular data to be generated from metadata on matching pages.
  43. */
  44. public class MetadataTableMacro extends MetadataUsingMacro {
  45. private static final int SUMMARISE_SUM = 1;
  46. private static final int SUMMARIZE_COUNT = 2;
  47. private static final int SUMMARIZE_MAX = 3;
  48. private static final int SUMMARIZE_MIN = 4;
  49. private static final int SUMMARIZE_TEXT = 5;
  50. protected static final String X_KEY = "x";
  51. protected static final String Y_KEY = "y";
  52. protected static final String VALUE_KEY = "value";
  53. protected static final String SUM_KEY = "summarise";
  54. protected static final String VALUE_NAME_KEY = "value-name";
  55. public MetadataTableMacro() {
  56. super("metadata-table");
  57. }
  58. public RenderMode getBodyRenderMode() {
  59. return RenderMode.NO_RENDER;
  60. }
  61. /**
  62. * The metadata table macro.
  63. * Usage: {metadata-table:x=xvalue|y=yvalue|value=value|...}
  64. * Where: * xvalue - The value that will be used for the x axis of the table. This value
  65. * must exist in {metadata} tags in at least two other pages
  66. * * yvalue - The value that will be used for the y axis of the table. This value
  67. * must exist in {metadata} tags in at least two other pages
  68. * * value - The value that will be used to populate the body of the table. Ideally there
  69. * will be a value for each x-y cell on the table. Empty cells will have a value of " ".
  70. * * Other parameters are the same as for the {metadata-report} macro.
  71. */
  72. @SuppressWarnings("unchecked")
  73. public String execute(Map parameters, String body, RenderContext renderContext) throws MacroException {
  74. try {
  75. String xValue = MacroUtils.getStringParameter(parameters, X_KEY, null);
  76. String yValue = MacroUtils.getStringParameter(parameters, Y_KEY, null);
  77. String tableValue = MacroUtils.getStringParameter(parameters, VALUE_KEY, null);
  78. String summarise = MacroUtils.getStringParameter(parameters, SUM_KEY, "SUM");
  79. StringBuffer html = new StringBuffer();
  80. int maxResults = MacroUtils.getIntParameter(parameters, MAX_RESULTS_PARAMETER, DEFAULT_MAX_RESULTS);
  81. List<MetadataContent> contents = getMatchingPages(parameters, getContentService(), renderContext, true);
  82. int totalResults = contents.size();
  83. @SuppressWarnings("unused")
  84. boolean truncated = false;
  85. if (totalResults > maxResults) {
  86. contents = contents.subList(0, maxResults);
  87. truncated = true;
  88. }
  89. //Set up the summarise constant for a little optimisation to save
  90. //a few string comparisons.
  91. int sum = SUMMARISE_SUM;
  92. if (summarise.compareToIgnoreCase("SUM") == 0) {
  93. sum = SUMMARISE_SUM;
  94. } else if (summarise.compareToIgnoreCase("COUNT") == 0) {
  95. sum = SUMMARIZE_COUNT;
  96. } else if (summarise.compareToIgnoreCase("MAX") == 0) {
  97. sum = SUMMARIZE_MAX;
  98. } else if (summarise.compareToIgnoreCase("MIN") == 0) {
  99. sum = SUMMARIZE_MIN;
  100. } else if (summarise.compareToIgnoreCase("TEXT") == 0) {
  101. sum = SUMMARIZE_TEXT;
  102. }
  103. List<MetadataValue> yValues = new ArrayList<MetadataValue>();
  104. List<MetadataValue> xValues = new ArrayList<MetadataValue>();
  105. HashMap<MetadataValue, HashMap<MetadataValue, Object>> table = new HashMap<MetadataValue, HashMap<MetadataValue, Object>>();
  106. HashMap<MetadataValue, Object> col;
  107. BigDecimal currentNumber;
  108. BigDecimal lastNumber = new BigDecimal(0);
  109. //Lookup all the x values
  110. for (MetadataContent content : contents) {
  111. MetadataValue y = content.getMetadataValue(yValue);
  112. MetadataValue x = content.getMetadataValue(xValue);
  113. MetadataValue currentValue = content.getMetadataValue(tableValue);
  114. Number tempNumber = currentValue != null ? currentValue.getValueAsNumber() : null;
  115. if (tempNumber == null) {
  116. currentNumber = new BigDecimal(0);
  117. } else {
  118. currentNumber = new BigDecimal(tempNumber.doubleValue());
  119. }
  120. if (!yValues.contains(y.getWikiSnippet())) {
  121. yValues.add(y);
  122. col = new HashMap<MetadataValue, Object>();
  123. table.put(y, col);
  124. } else {
  125. col = table.get(y);
  126. }
  127. if (!xValues.contains(x.getWikiSnippet())) {
  128. xValues.add(x);
  129. }
  130. //Setup some initial values
  131. if (sum != SUMMARIZE_TEXT) {
  132. if (col.get(x) != null) {
  133. lastNumber = (BigDecimal)col.get(x);
  134. } else {
  135. if (sum == SUMMARIZE_MIN) {
  136. lastNumber = new BigDecimal(Integer.MAX_VALUE);
  137. } else if (sum == SUMMARIZE_MIN) {
  138. lastNumber = new BigDecimal(Integer.MAX_VALUE);
  139. } else {
  140. lastNumber = new BigDecimal(0);
  141. }
  142. }
  143. }
  144. switch (sum) {
  145. case SUMMARIZE_TEXT: {
  146. col.put(x, MetadataValue.getWikiSnippet(currentValue));
  147. break;
  148. }
  149. case SUMMARIZE_COUNT: {
  150. col.put(x, new BigDecimal(lastNumber.intValue() + 1));
  151. break;
  152. }
  153. case SUMMARIZE_MIN: {
  154. if (lastNumber.compareTo(currentNumber) >= 0) {
  155. col.put(x, currentNumber);
  156. }
  157. break;
  158. }
  159. case SUMMARIZE_MAX: {
  160. if (lastNumber.compareTo(currentNumber) < 0) {
  161. col.put(x, currentNumber);
  162. }
  163. break;
  164. }
  165. default: { //Default is SUMMARISE_SUM
  166. col.put(x, new BigDecimal(currentNumber.intValue() + lastNumber.intValue()));
  167. }
  168. }
  169. }
  170. //Sort the y axis
  171. try {
  172. Collections.sort(yValues);
  173. }
  174. catch (Exception e) {
  175. //Can't sort the table's y axis.
  176. }
  177. //Sort the x axis
  178. try {
  179. Collections.sort(xValues);
  180. }
  181. catch (Exception e) {
  182. //Can't sort the table's x axis.
  183. }
  184. html.append("<table class='confluencetable'>\n");
  185. html.append("<tr>");
  186. html.append("<th class='confluenceTh'>");
  187. html.append(xValue);
  188. html.append("</th>");
  189. for (int i = 0; i < yValues.size(); i++) {
  190. html.append("<th class='confluenceTh'>");
  191. html.append(yValues.get(i));
  192. html.append("</th>");
  193. }
  194. html.append("</tr>");
  195. for (int i = 0; i < xValues.size(); i++) {
  196. html.append("<tr>\n");
  197. html.append("<th class='confluenceTh'>");
  198. html.append(xValues.get(i));
  199. html.append("</th>");
  200. for (int j = 0; j < yValues.size(); j++) {
  201. html.append("<td class='confluenceTd'>");
  202. try {
  203. col = table.get(yValues.get(j));
  204. if (col != null) {
  205. html.append(col.get(xValues.get(i)));
  206. } else {
  207. html.append(" ");
  208. }
  209. } catch (Exception e) {
  210. html.append(" ");
  211. }
  212. html.append("</td>\n");
  213. }
  214. html.append("</tr>\n");
  215. }
  216. html.append("</table>\n");
  217. return html.toString();
  218. } catch (Exception e) {
  219. return MacroUtils.showRenderedExceptionString(parameters, "Unable to render metadata table macro", e);
  220. }
  221. }
  222. }