View Javadoc

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