/plugin/src/main/java/com/atlassian/plugin/remotable/plugin/module/ConditionProcessor.java

https://bitbucket.org/rodogu/remotable-plugins · Java · 166 lines · 148 code · 15 blank · 3 comment · 16 complexity · 0ebd193464eb48907f1cfe24dd6231fa MD5 · raw file

  1. package com.atlassian.plugin.remotable.plugin.module;
  2. import com.atlassian.plugin.AutowireCapablePlugin;
  3. import com.atlassian.plugin.Plugin;
  4. import com.atlassian.plugin.PluginParseException;
  5. import com.atlassian.plugin.osgi.bridge.external.PluginRetrievalService;
  6. import com.atlassian.plugin.remotable.plugin.util.node.Node;
  7. import com.atlassian.plugin.remotable.spi.module.RemoteCondition;
  8. import com.atlassian.plugin.remotable.spi.product.ProductAccessor;
  9. import com.atlassian.plugin.web.Condition;
  10. import com.atlassian.plugin.web.conditions.ConditionLoadingException;
  11. import com.atlassian.plugin.web.descriptors.ConditionElementParser;
  12. import com.google.common.base.Function;
  13. import com.google.common.collect.Sets;
  14. import org.dom4j.Element;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.stereotype.Component;
  17. import javax.annotation.Nullable;
  18. import java.util.Collections;
  19. import java.util.List;
  20. import static com.google.common.collect.Lists.newArrayList;
  21. import static com.google.common.collect.Lists.transform;
  22. import static org.apache.commons.lang.StringUtils.escape;
  23. import static org.apache.commons.lang.StringUtils.join;
  24. import static org.dom4j.DocumentHelper.createElement;
  25. /**
  26. * Processes conditions, handling static and remote conditions via big pipe
  27. */
  28. @Component
  29. public class ConditionProcessor
  30. {
  31. private final ProductAccessor productAccessor;
  32. private final AutowireCapablePlugin remotablePlugin;
  33. @Autowired
  34. public ConditionProcessor(ProductAccessor productAccessor, PluginRetrievalService pluginRetrievalService)
  35. {
  36. this.productAccessor = productAccessor;
  37. this.remotablePlugin = (AutowireCapablePlugin) pluginRetrievalService.getPlugin();
  38. }
  39. public Condition process(Node oldConfig, Element newConfig, String pluginKey)
  40. {
  41. return process(oldConfig, newConfig, pluginKey, null);
  42. }
  43. public Condition process(Node oldConfig, Element newConfig, String pluginKey, String toHideSelector)
  44. {
  45. List<String> contextParamKeys = getContextParameters(oldConfig);
  46. newConfig.elements("conditions").clear();
  47. Node conditions = oldConfig.get("conditions");
  48. String remoteConditionUrl = null;
  49. if (conditions.exists())
  50. {
  51. for (Node cElement : conditions.getChildren("condition"))
  52. {
  53. Node cName = cElement.get("name");
  54. Node cUrl = cElement.get("url");
  55. if (cName.exists() && cUrl.exists())
  56. {
  57. throw new PluginParseException("Name and url cannot be defined on a condition");
  58. }
  59. else if (!cName.exists() && !cUrl.exists())
  60. {
  61. throw new PluginParseException("Either the name or url must be defined on a condition");
  62. }
  63. Element condElement = newConfig.addElement("condition");
  64. if (Boolean.parseBoolean(escape(cElement.get("invert").asString(null))))
  65. {
  66. condElement.addAttribute("invert", "true");
  67. }
  68. if (cName.exists())
  69. {
  70. condElement.addAttribute("class", productAccessor.getConditions().get(cName.asString()).getName());
  71. for (Node child : cElement.getChildren("param"))
  72. {
  73. condElement.add(createElement("param")
  74. .addAttribute("name", child.get("name").asString())
  75. .addText(child.asString()));
  76. }
  77. }
  78. else
  79. {
  80. remoteConditionUrl = cUrl.asString();
  81. if (toHideSelector == null)
  82. {
  83. String hash = createUniqueUrlHash(pluginKey, remoteConditionUrl);
  84. toHideSelector = "." + hash;
  85. }
  86. String paramList = contextParamKeys.isEmpty() ? "" : join(contextParamKeys, ",");
  87. condElement.addAttribute("class", RemoteCondition.class.getName());
  88. condElement.addElement("param").addAttribute("name", "pluginKey").addText(pluginKey).getParent()
  89. .addElement("param").addAttribute("name", "url").addText(remoteConditionUrl).getParent()
  90. .addElement("param").addAttribute("name", "contextParams").addText(paramList).getParent()
  91. .addElement("param").addAttribute("name", "toHideSelector").addText(
  92. toHideSelector);
  93. }
  94. }
  95. }
  96. ConditionElementParser conditionElementParser = new ConditionElementParser(new ConditionElementParser.ConditionFactory()
  97. {
  98. @Override
  99. public Condition create(String className, Plugin plugin) throws
  100. ConditionLoadingException
  101. {
  102. try
  103. {
  104. return (Condition) remotablePlugin.autowire(((Plugin) remotablePlugin).loadClass
  105. (className, getClass()));
  106. }
  107. catch (ClassNotFoundException e)
  108. {
  109. throw new ConditionLoadingException(e);
  110. }
  111. }
  112. });
  113. if (newConfig.elements("condition").size() > 1)
  114. {
  115. Element root = newConfig.addElement("conditions").addAttribute("type", "AND");
  116. for (Element cond : (List<Element>) newConfig.elements("condition"))
  117. {
  118. root.add(cond.detach());
  119. }
  120. }
  121. Condition aggregateCondition = conditionElementParser.makeConditions((Plugin) remotablePlugin,
  122. newConfig,
  123. ConditionElementParser.CompositeType.AND);
  124. return remoteConditionUrl != null ? new ContainingRemoteCondition(aggregateCondition, remoteConditionUrl) :
  125. aggregateCondition;
  126. }
  127. public String createUniqueUrlHash(String pluginKey, String cUrl)
  128. {
  129. return "ap-hash-" + (cUrl + ":" + pluginKey).hashCode();
  130. }
  131. public Plugin getLoadablePlugin(Plugin plugin)
  132. {
  133. return new ConditionLoadingPlugin(remotablePlugin, plugin, Sets.<Class<?>>newHashSet(productAccessor.getConditions().values()));
  134. }
  135. private List<String> getContextParameters(Node oldConfig)
  136. {
  137. Node contextParameters = oldConfig.get("context-parameters");
  138. if (contextParameters.exists())
  139. {
  140. return transform(newArrayList(contextParameters.getChildren("context-parameter")), new Function<Node, String>()
  141. {
  142. @Override
  143. public String apply(@Nullable Node input)
  144. {
  145. return input.get("name").asString();
  146. }
  147. } );
  148. }
  149. return Collections.emptyList();
  150. }
  151. }