View Javadoc
1   package com.atlassian.plugin.web.descriptors;
2   
3   import com.atlassian.plugin.Plugin;
4   import com.atlassian.plugin.PluginParseException;
5   import com.atlassian.plugin.hostcontainer.HostContainer;
6   import com.atlassian.plugin.module.ModuleFactory;
7   import com.atlassian.plugin.util.validation.ValidationPattern;
8   import com.atlassian.plugin.web.WebInterfaceManager;
9   import com.atlassian.plugin.web.model.WebPanel;
10  import com.google.common.base.Supplier;
11  import com.google.common.collect.Maps;
12  import org.dom4j.Element;
13  
14  import java.io.IOException;
15  import java.io.Writer;
16  import java.util.Map;
17  
18  import static com.atlassian.plugin.util.validation.ValidationPattern.test;
19  
20  /**
21   * <p>
22   * The web panel module declares a single web panel in atlassian-plugin.xml. Its
23   * XML element contains a location string that should match existing locations
24   * in the host application where web panels can be embedded.
25   * </p>
26   * <p>
27   * A web panel also contains a single resource child element that contains the
28   * contents of the web panel. This can be plain HTML, or a (velocity) template
29   * to provide dynamic content.
30   * </p>
31   * <p>
32   * A resource element's <code>type</code> attribute identifies the format of the
33   * panel's content (currently "static" and "velocity" are supported) which
34   * allows the plugin framework to use the appropriate
35   * {@link com.atlassian.plugin.web.renderer.WebPanelRenderer}.
36   * </p>
37   * <p>
38   * A web panel's resource element can either contain its contents embedded in
39   * the resource element itself, as part of the <code>atlassian-plugin.xml</code>
40   * file, or it can link to a file on the classpath when the
41   * <code>location</code> attribute is used.
42   * </p>
43   * <b>Examples</b>
44   * <p>
45   * A web panel that contains static, embedded HTML:
46   *
47   * <pre>
48   *     &lt;web-panel key="myPanel" location="general"&gt;
49   *         &lt;resource name="view" type="static"&gt;&lt;![CDATA[&lt;b&gt;Hello World!&lt;/b&gt;]]&gt;&lt;/resource&gt;
50   *     &lt;/web-panel&gt;
51   * </pre>
52   * <p>
53   * A web panel that contains an embedded velocity template:
54   *
55   * <pre>
56   *     &lt;web-panel key="myPanel" location="general"&gt;
57   *         &lt;resource name="view" type="velocity"&gt;&lt;![CDATA[#set($name = 'foo')My name is $name]]&gt;&lt;/resource&gt;
58   *     &lt;/web-panel&gt;
59   * </pre>
60   *
61   * <p>
62   * A web panel that contains uses a velocity template that is on the classpath
63   * (part of the plugin's jar file):
64   *
65   * <pre>
66   *     &lt;web-panel key="myPanel" location="general"&gt;
67   *         &lt;resource name="view" type="velocity" location="templates/pie.vm"/&gt;
68   *     &lt;/web-panel&gt;
69   * </pre>
70   *
71   * <p>
72   * Finally it is also possible to provide your own custom class that is
73   * responsible for producing the panel's HTML, by using the descriptor's
74   * <code>class</code> attribute:
75   *
76   * <pre>
77   *     &lt;web-panel key="myPanel" location="general" class="com.example.FooWebPanel"/&gt;
78   * </pre>
79   * <p>
80   * Note that <code>FooWebPanel</code> must implement
81   * {@link com.atlassian.plugin.web.model.WebPanel}.
82   *
83   * @since 2.5.0
84   */
85  public class DefaultWebPanelModuleDescriptor extends AbstractWebFragmentModuleDescriptor<WebPanel> implements WebPanelModuleDescriptor {
86      /**
87       * Host applications should use this string when registering the web panel
88       * module descriptor.
89       */
90      public static final String XML_ELEMENT_NAME = "web-panel";
91  
92      private WebPanelSupplierFactory webPanelSupplierFactory;
93  
94      /**
95       * These suppliers are used to delay instantiation because the required
96       * spring beans are not available for injection during the init() phase.
97       */
98      private Supplier<WebPanel> webPanelFactory;
99  
100     private int weight;
101     private String location;
102 
103     public DefaultWebPanelModuleDescriptor(final HostContainer hostContainer, final ModuleFactory moduleClassFactory, final WebInterfaceManager webInterfaceManager) {
104         super(moduleClassFactory, webInterfaceManager);
105         this.webPanelSupplierFactory = new WebPanelSupplierFactory(this, hostContainer, moduleFactory);
106         this.webInterfaceManager = webInterfaceManager;
107     }
108 
109     @Override
110     public void init(final Plugin plugin, final Element element) throws PluginParseException {
111         super.init(plugin, element);
112 
113         weight = WeightElementParser.getWeight(element);
114         location = element.attributeValue("location");
115 
116         webPanelFactory = webPanelSupplierFactory.build(moduleClassName);
117     }
118 
119     private class ContextAwareWebPanel implements WebPanel {
120         private final WebPanel delegate;
121 
122         private ContextAwareWebPanel(WebPanel delegate) {
123             this.delegate = delegate;
124         }
125 
126         public String getHtml(final Map<String, Object> context) {
127             return delegate.getHtml(getContextProvider().getContextMap(Maps.newHashMap(context)));
128         }
129 
130         public void writeHtml(Writer writer, Map<String, Object> context) throws IOException {
131             delegate.writeHtml(writer, getContextProvider().getContextMap(Maps.newHashMap(context)));
132         }
133     }
134 
135     @Override
136     protected void provideValidationRules(final ValidationPattern pattern) {
137         super.provideValidationRules(pattern);
138         pattern.rule(test("@location").withError("The Web Panel location attribute is required."));
139     }
140 
141     public String getLocation() {
142         return location;
143     }
144 
145     public int getWeight() {
146         return weight;
147     }
148 
149     @Override
150     public WebPanel getModule() {
151         return new ContextAwareWebPanel(webPanelFactory.get());
152     }
153 
154     @Override
155     public void enabled() {
156         super.enabled();
157         webInterfaceManager.refresh();
158     }
159 
160     @Override
161     public void disabled() {
162         webInterfaceManager.refresh();
163         super.disabled();
164     }
165 }