Commits

Ben Woskow committed 78f4ac5

UPM-1852 updating generated license admin servlet in the tutorial such that developers will be more likely to want to reuse it

  • Participants
  • Parent commits 52b0a17

Comments (0)

Files changed (6)

                         <Import-Package>
                             com.atlassian.plugin*;version="0.0",
                             com.atlassian.sal*;version="0.0",
+                            com.atlassian.templaterenderer*;version="0.0",
                             com.google.common*;version="1.0",
                             javax.servlet*;version="0.0",
                             org.apache.commons*;version="0.0",
                             <version>${upm.license.compatibility.version}</version>
                         </bundledArtifact>
                     </bundledArtifacts>
+                    <systemPropertyVariables>
+                        <mac.baseurl>https://intsys-staging.atlassian.com/my</mac.baseurl>
+                    </systemPropertyVariables>
                 </configuration>
             </plugin>
             <plugin>
             <version>2.4</version>
             <scope>provided</scope>
         </dependency>
-
+        <dependency>
+            <groupId>com.atlassian.templaterenderer</groupId>
+            <artifactId>atlassian-template-renderer-api</artifactId>
+            <version>1.0.5</version>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
     <properties>
         <amps.version>3.7.2</amps.version>

File src/main/java/com/example/plugins/tutorial/servlet/HelloWorldServlet.java

  * existence/validity at a plugin entry point.
  *
  * This servlet can be reached at http://localhost:2990/jira/plugins/servlet/helloworldservlet
+ *
+ * Note that Atlassian does not recommend writing servlets in this manner. You should really look
+ * into using a templating library such as Velocity. This servlet is written this way solely for simplicity purposes.
  */
 public class HelloWorldServlet extends HttpServlet
 {

File src/main/java/com/example/plugins/tutorial/servlet/LicenseServlet.java

 
 import java.io.IOException;
 import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletResponse;
 
 import com.atlassian.sal.api.ApplicationProperties;
+import com.atlassian.sal.api.auth.LoginUriProvider;
+import com.atlassian.sal.api.message.I18nResolver;
+import com.atlassian.sal.api.user.UserManager;
+import com.atlassian.templaterenderer.TemplateRenderer;
 import com.atlassian.upm.api.license.entity.PluginLicense;
 import com.atlassian.upm.api.util.Option;
 import com.atlassian.upm.license.storage.lib.AtlassianMarketplaceUriFactory;
 import org.apache.commons.lang.StringUtils;
 
 /**
- * A simple license administration servlet that demonstrates how to use
- * {@link ThirdPartyPluginLicenseStorageManager} to:
+ * A license administration servlet that uses {@link ThirdPartyPluginLicenseStorageManager} to:
  *  - get the current plugin license,
  *  - update the plugin license,
  *  - remove the plugin license,
  *  - and properly handle if a licensing-aware UPM is detected.
  *
  * This servlet can be reached at http://localhost:2990/jira/plugins/servlet/licenseservlet
- *
- * Note that Atlassian does not recommend writing servlets in this manner. You should really look
- * into using a templating library such as Velocity. This servlet is written this way solely for simplicity purposes.
  */
 public class LicenseServlet extends HttpServlet
 {
+    private static final String TEMPLATE = "license-admin.vm";
+
     private final ThirdPartyPluginLicenseStorageManager licenseManager;
     private final AtlassianMarketplaceUriFactory uriFactory;
     private final ApplicationProperties applicationProperties;
+    private final TemplateRenderer renderer;
+    private final LoginUriProvider loginUriProvider;
+    private final UserManager userManager;
+    private final I18nResolver i18nResolver;
 
     public LicenseServlet(ThirdPartyPluginLicenseStorageManager licenseManager,
                               AtlassianMarketplaceUriFactory uriFactory,
-                              ApplicationProperties applicationProperties)
+                              ApplicationProperties applicationProperties,
+                              TemplateRenderer renderer,
+                              LoginUriProvider loginUriProvider,
+                              UserManager userManager,
+                              I18nResolver i18nResolver)
     {
         this.licenseManager = licenseManager;
         this.uriFactory = uriFactory;
         this.applicationProperties = applicationProperties;
+        this.renderer = renderer;
+        this.loginUriProvider = loginUriProvider;
+        this.userManager = userManager;
+        this.i18nResolver = i18nResolver;
     }
 
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
     {
-        resp.setContentType("text/html");
-        resp.getWriter().write("<html><body>");
-        outputBody(resp);
-        resp.getWriter().write("</body></html>");
-        resp.getWriter().close();
+        if (!hasAdminPermission())
+        {
+            redirectToLogin(req, resp);
+            return;
+        }
+
+        final Map<String, Object> context = initVelocityContext(resp);
+        addEligibleMarketplaceButtons(context);
+        renderer.render(TEMPLATE, context, resp.getWriter());
     }
 
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
     {
-        resp.setContentType("text/html");
-        resp.getWriter().write("<html><body><b>");
+        if (!hasAdminPermission())
+        {
+            redirectToLogin(req, resp);
+            return;
+        }
 
-        try
+        final Map<String, Object> context = initVelocityContext(resp);
+
+        if (!context.containsKey("errorMessage"))
         {
-            if (!licenseManager.isUpmLicensingAware())
+            try
             {
-                String license = req.getParameter("license");
-                if (!StringUtils.isEmpty(license))
+                if (!licenseManager.isUpmLicensingAware())
                 {
-                    //we have a non-empty license parameter - let's update the license if it is valid.
+                    String license = req.getParameter("license");
                     Option<PluginLicense> validatedLicense = licenseManager.validateLicense(license);
-                    if (validatedLicense.isDefined())
+
+                    //we have an empty/null license parameter - let's remove the stored license.
+                    if (StringUtils.isEmpty(license))
+                    {
+                        licenseManager.removeRawLicense();
+                        context.put("successMessage", i18nResolver.getText("plugin.license.storage.admin.license.remove"));
+                        context.put("license", licenseManager.getLicense());
+                    }
+                    //we have a non-empty license parameter - let's update the license if it is valid.
+                    else if (validatedLicense.isDefined())
                     {
                         licenseManager.setRawLicense(license);
-                        resp.getWriter().write("Valid license. License has been updated.");
+                        if (validatedLicense.get().getError().isDefined())
+                        {
+                            context.put("warningMessage", i18nResolver.getText("plugin.license.storage.admin.license.update.invalid"));
+                        }
+                        else
+                        {
+                            context.put("successMessage", i18nResolver.getText("plugin.license.storage.admin.license.update"));
+                        }
+                        context.put("license", licenseManager.getLicense());
                     }
+                    //we have an invalid license - do nothing.
                     else
                     {
-                        resp.getWriter().write("Invalid license. License has not been updated.");
+                        context.put("errorMessage", i18nResolver.getText("plugin.license.storage.admin.license.invalid"));
                     }
                 }
-                else
-                {
-                    //we have an empty/null license parameter - let's remove the stored license
-                    licenseManager.removeRawLicense();
-                    resp.getWriter().write("License has been removed.");
-                }
             }
-            else
+            catch (PluginLicenseStoragePluginUnresolvedException e)
             {
-                //don't allow POSTs to occur to our license servlet if UPM is licensing-aware
-                resp.getWriter().write("Nice try! You cannot update your plugin license with this API when UPM is licensing-aware.");
+                context.put("errorMessage", i18nResolver.getText("plugin.license.storage.admin.plugin.unavailable"));
+                context.put("storagePluginIsAvailable", false);
+            }
+        }
+
+        addEligibleMarketplaceButtons(context); //must be invoked *after* the license update has occurred.
+        renderer.render(TEMPLATE, context, resp.getWriter());
+    }
+
+    private Map<String, Object> initVelocityContext(HttpServletResponse resp)
+    {
+        resp.setContentType("text/html;charset=utf-8");
+        URI servletUri = URI.create(applicationProperties.getBaseUrl() + "/plugins/servlet/licenseservlet");
+
+        final Map<String, Object> context = new HashMap<String, Object>();
+
+        resp.setContentType("text/html;charset=utf-8");
+        context.put("servletUri", servletUri);
+        context.put("storagePluginIsAvailable", true);
+
+        try
+        {
+            context.put("license", licenseManager.getLicense());
+            context.put("upmLicensingAware", licenseManager.isUpmLicensingAware());
+            context.put("pluginKey", licenseManager.getPluginKey());
+            if (licenseManager.isUpmLicensingAware())
+            {
+                context.put("warningMessage", i18nResolver.getText("plugin.license.storage.admin.upm.licensing.aware",
+                                                                   licenseManager.getPluginManagementUri()));
             }
         }
         catch (PluginLicenseStoragePluginUnresolvedException e)
         {
-            resp.getWriter().write("<br>Sorry, but we cannot find the required licensing support to execute the requested operation. "
-                    + "Please ensure that the Plugin License Storage plugin is installed and enabled. Restarting this plugin " +
-                    		"should resolve the problem.");
+            context.put("errorMessage", i18nResolver.getText("plugin.license.storage.admin.plugin.unavailable"));
+            context.put("storagePluginIsAvailable", false);
         }
 
-        resp.getWriter().write("</b>");
-        outputBody(resp);
-        resp.getWriter().write("</body></html>");
-        resp.getWriter().close();
+        return context;
     }
 
-    private void outputBody(HttpServletResponse resp) throws ServletException, IOException
+    private void addEligibleMarketplaceButtons(Map<String, Object> context)
     {
         URI servletUri = URI.create(applicationProperties.getBaseUrl() + "/plugins/servlet/licenseservlet");
+
         try
         {
-            resp.getWriter().write("<br><br>UPM is licensing-aware: " + licenseManager.isUpmLicensingAware());
-            resp.getWriter().write("<br>Plugin key: " + licenseManager.getPluginKey());
-    
-            if (!licenseManager.isUpmLicensingAware())
-            {
-                resp.getWriter().write("<br><br>Update your license");
-                resp.getWriter().write("<br><form action=\"" + servletUri.toASCIIString() + "\" method=\"POST\">");
-                resp.getWriter().write("<textarea name=\"license\" cols=\"80\" rows=\"10\">");
-                for (String storedRawLicense : licenseManager.getRawLicense())
-                {
-                    //enter the stored license into the textarea, if the license has been stored
-                    resp.getWriter().write(storedRawLicense);
-                }
-                resp.getWriter().write("</textarea>");
-                resp.getWriter().write("<br><input type=\"submit\" value=\"Save\" />");
-                resp.getWriter().write("</form>");
+            boolean eligibleButtons = false;
 
-                //Display appropriate marketplace buttons
-                resp.getWriter().write("<br>");
-                if (uriFactory.isPluginBuyable())
-                {
-                    outputMarketplaceButton(uriFactory.getBuyPluginUri(servletUri), "Buy", resp);
-                }
-                if (uriFactory.isPluginTryable())
-                {
-                    outputMarketplaceButton(uriFactory.getTryPluginUri(servletUri), "Try", resp);
-                }
-                if (uriFactory.isPluginRenewable())
-                {
-                    outputMarketplaceButton(uriFactory.getRenewPluginUri(servletUri), "Renew", resp);
-                }
-                if (uriFactory.isPluginUpgradable())
-                {
-                    outputMarketplaceButton(uriFactory.getUpgradePluginUri(servletUri), "Upgrade", resp);
-                }
+            if (uriFactory.isPluginBuyable())
+            {
+                context.put("buyPluginUri", uriFactory.getBuyPluginUri(servletUri));
+                eligibleButtons = true;
             }
-            else
+            if (uriFactory.isPluginTryable())
             {
-                resp.getWriter().write("<br>Cannot modify plugin licenses with this API when UPM is licensing-aware. Please use ");
-                resp.getWriter().write("<a href=\"" + licenseManager.getPluginManagementUri() + "\">UPM's licensing UI</a>.");
+                context.put("tryPluginUri", uriFactory.getTryPluginUri(servletUri));
+                eligibleButtons = true;
             }
+            if (uriFactory.isPluginRenewable())
+            {
+                context.put("renewPluginUri", uriFactory.getRenewPluginUri(servletUri));
+                eligibleButtons = true;
+            }
+            if (uriFactory.isPluginUpgradable())
+            {
+                context.put("upgradePluginUri", uriFactory.getUpgradePluginUri(servletUri));
+                eligibleButtons = true;
+            }
+
+            context.put("eligibleButtons", eligibleButtons);
         }
         catch (PluginLicenseStoragePluginUnresolvedException e)
         {
-            resp.getWriter().write("<br>Sorry, but we cannot find the required licensing support to execute the requested operation. "
-                    + "Please ensure that the Plugin License Storage plugin is installed and enabled. Restarting this plugin " +
-                            "should resolve the problem.");
+            context.put("errorMessage", i18nResolver.getText("plugin.license.storage.admin.plugin.unavailable"));
+            context.put("storagePluginIsAvailable", false);
+        }
+    }
+
+    private boolean hasAdminPermission()
+    {
+        String user = userManager.getRemoteUsername();
+        try
+        {
+            return user != null && (userManager.isAdmin(user) || userManager.isSystemAdmin(user));
+        }
+        catch(NoSuchMethodError e)
+        {
+            // userManager.isAdmin(String) was not added until SAL 2.1.
+            // We need this check to ensure backwards compatibility with older product versions.
+            return user != null && userManager.isSystemAdmin(user);
         }
     }
 
-    private void outputMarketplaceButton(URI buttonUri, String buttonText, HttpServletResponse resp) throws IOException
+    private void redirectToLogin(HttpServletRequest request, HttpServletResponse response) throws IOException
     {
-        resp.getWriter().write("<form action=\"" + buttonUri + "\" method=\"POST\">");
-        resp.getWriter().write("<input type=\"submit\" value=\"" + buttonText + "\" />");
-        resp.getWriter().write("</form>");
+        response.sendRedirect(loginUriProvider.getLoginUri(URI.create(request.getRequestURL().toString())).toASCIIString());
     }
 }

File src/main/resources/atlassian-plugin.xml

   <component-import key="pluginController" interface="com.atlassian.plugin.PluginController"/>
   <component-import key="txTemplate" interface="com.atlassian.sal.api.transaction.TransactionTemplate"/>
   <component-import key="applicationProperties" interface="com.atlassian.sal.api.ApplicationProperties"/>
+  <component-import key="templateRenderer" interface="com.atlassian.templaterenderer.TemplateRenderer"/>
   <component-import key="pluginSettingsFactory" interface="com.atlassian.sal.api.pluginsettings.PluginSettingsFactory"/>
+  <component-import key="loginUriProvider" interface="com.atlassian.sal.api.auth.LoginUriProvider" />
+  <component-import key="userManager" interface="com.atlassian.sal.api.user.UserManager" />
+  <component-import key="i18nResolver" interface="com.atlassian.sal.api.message.I18nResolver" />
 
   <component key="pluginLicenseStoragePluginInstaller" class="com.atlassian.upm.license.storage.lib.PluginLicenseStoragePluginInstaller"/>
   <component key="thirdPartyPluginLicenseStorageManager" class="com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl"/>
   </servlet>
 
   <resource type="i18n" name="i18n" location="atlassian-plugin"/>
+  <resource type="i18n" name="license-i18n" location="license-admin"/>
 
 </atlassian-plugin>

File src/main/resources/license-admin.properties

+
+plugin.license.storage.admin.title={0} License Administration
+
+plugin.license.storage.admin.plugin.unavailable=Sorry, but we cannot find the required licensing support to execute the requested operation. Please ensure that the Plugin License Storage plugin is installed and enabled. Restarting this plugin should resolve the problem.
+plugin.license.storage.admin.upm.licensing.aware=Sorry, you cannot update your plugin license on this screen. Please use the <a href=''{0}''>Plugin Manager</a> instead.
+plugin.license.storage.admin.license.update=The license you submitted is valid. Your license has been successfully updated.
+plugin.license.storage.admin.license.update.invalid=The license you submitted has an error. Your license has been updated. See below for more information.
+plugin.license.storage.admin.license.remove=Your license has successfully been removed.
+plugin.license.storage.admin.license.invalid=The license you have submitted is invalid. Your license has not been updated.
+
+plugin.license.storage.admin.license.action.new.title=Enter a new license
+plugin.license.storage.admin.license.action.acquire.title=Acquire a new license
+plugin.license.storage.admin.license.action.update.title=Update your license
+plugin.license.storage.admin.license.action.buy=Buy
+plugin.license.storage.admin.license.action.try=Try
+plugin.license.storage.admin.license.action.renew=Renew
+plugin.license.storage.admin.license.action.upgrade=Upgrade
+plugin.license.storage.admin.license.action.update=Update
+
+plugin.license.storage.admin.license.details=License Details
+plugin.license.storage.admin.license.attribute.status.title=Status
+plugin.license.storage.admin.license.attribute.status.invalid.eval=Invalid {0} evaluation license with a {1} error
+plugin.license.storage.admin.license.attribute.status.valid.eval=Valid {0} evaluation license
+plugin.license.storage.admin.license.attribute.status.invalid.noneval=Invalid {0} license with a {1} error
+plugin.license.storage.admin.license.attribute.status.valid.noneval=Valid {0} license
+plugin.license.storage.admin.license.attribute.status.unlicensed=Unlicensed
+plugin.license.storage.admin.license.attribute.pluginkey.title=Plugin Key
+plugin.license.storage.admin.license.attribute.maxusers.title=Maximum Number of Users
+plugin.license.storage.admin.license.attribute.maxusers.unlimited=Unlimited
+plugin.license.storage.admin.license.attribute.creationdate.title=Creation Date
+plugin.license.storage.admin.license.attribute.expirationdate.title=Expiration Date
+plugin.license.storage.admin.license.attribute.maintenanceexpirationdate.title=Maintenance Expiration date
+plugin.license.storage.admin.license.attribute.description.title=Description
+plugin.license.storage.admin.license.attribute.organization.title=Organization
+plugin.license.storage.admin.license.attribute.serverid.title=Server Id
+plugin.license.storage.admin.license.attribute.sen.title=Support Entitlement Number (SEN)
+
+plugin.license.storage.admin.license.type.ACADEMIC=academic
+plugin.license.storage.admin.license.type.COMMERCIAL=commercial
+plugin.license.storage.admin.license.type.COMMUNITY=community
+plugin.license.storage.admin.license.type.DEMONSTRATION=demonstration
+plugin.license.storage.admin.license.type.DEVELOPER=developer
+plugin.license.storage.admin.license.type.NON_PROFIT=non-profit
+plugin.license.storage.admin.license.type.OPEN_SOURCE=open source
+plugin.license.storage.admin.license.type.PERSONAL=personal
+plugin.license.storage.admin.license.type.STARTER=starter
+plugin.license.storage.admin.license.type.HOSTED=hosted
+plugin.license.storage.admin.license.type.TESTING=testing
+
+plugin.license.storage.admin.license.error.EXPIRED=expired
+plugin.license.storage.admin.license.error.TYPE_MISMATCH=type mismatch
+plugin.license.storage.admin.license.error.USER_MISMATCH=user mismatch
+plugin.license.storage.admin.license.error.VERSION_MISMATCH=version mismatch

File src/main/resources/license-admin.vm

+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+    <head>
+        <title>$i18n.getText("plugin.license.storage.admin.title", "Tutorial Plugin")</title>
+        <meta name='decorator' content='atl.admin'/>
+    </head>
+    <body>
+        <h1>$i18n.getText("plugin.license.storage.admin.title", "Tutorial Plugin")</h1>
+            ## Because these message may embed html tags that we don't want to be overescaped
+            #set($successMessageWithHtml = $successMessage)
+            #set($errorMessageWithHtml = $errorMessage)
+            #set($warningMessageWithHtml = $warningMessage)
+
+            #set($dateFormat = "MMMM dd, yyyy")
+
+            #if ($successMessageWithHtml)
+            <div class="aui-message success"><span class="aui-icon icon-success"></span>$successMessageWithHtml</div>
+            #end
+            #if ($errorMessageWithHtml)
+            <div class="aui-message error"><span class="aui-icon icon-error"></span>$errorMessageWithHtml</div>
+            #end
+            #if ($warningMessageWithHtml)
+            <div class="aui-message warning"><span class="aui-icon icon-warning"></span>$warningMessageWithHtml</div>
+            #end
+
+            #if (!$upmLicensingAware && $storagePluginIsAvailable)
+            <h4>$i18n.getText("plugin.license.storage.admin.license.details")</h4>
+            <table class="aui">
+                <tbody>
+                    <tr>
+                        <td>$i18n.getText("plugin.license.storage.admin.license.attribute.status.title")</td>
+                        #if ($license.isDefined())
+                            #if ($license.get().valid)
+                            #set($validityText = "valid")
+                            #else
+                            #set($validityText = "invalid")
+                            #end
+
+                            #if ($license.get().evaluation)
+                            #set($typeText = "eval")
+                            #else
+                            #set($typeText =  "noneval")
+                            #end
+
+                            #set ($statusKey = "plugin.license.storage.admin.license.attribute.status." + $validityText + "." + $typeText)
+                            #set ($licenseTypeKey = "plugin.license.storage.admin.license.type." + $license.get().licenseType.name())
+
+                            #if ($license.get().error.isDefined())
+                                #set ($errorKey = "plugin.license.storage.admin.license.error." + $license.get().error.get().name())
+                                <td>$i18n.getText($statusKey, $i18n.getText($licenseTypeKey), $i18n.getText($errorKey))</td>
+                            #else
+                                <td>$i18n.getText($statusKey, $i18n.getText($licenseTypeKey))</td>
+                            #end
+                        #else
+                        <td>$i18n.getText("plugin.license.storage.admin.license.attribute.status.unlicensed")</td>
+                        #end
+                    </tr>
+                    <tr>
+                        <td>$i18n.getText("plugin.license.storage.admin.license.attribute.pluginkey.title")</td>
+                        <td>$pluginKey</td>
+                    </tr>
+
+                    #if ($license.isDefined())
+                        <tr>
+                            <td>$i18n.getText("plugin.license.storage.admin.license.attribute.maxusers.title")</td>
+                            #if ($license.get().unlimitedNumberOfUsers)
+                            <td>$i18n.getText("plugin.license.storage.admin.license.attribute.maxusers.unlimited")</td>
+                            #else
+                            <td>$license.get().maximumNumberOfUsers.get()</td>
+                            #end
+                        </tr>
+                        <tr>
+                            <td>$i18n.getText("plugin.license.storage.admin.license.attribute.creationdate.title")</td>
+                            <td>$license.get().creationDate.toString($dateFormat)</td>
+                        </tr>
+                        #if ($license.expiryDate.isDefined())
+                        <tr>
+                            <td>$i18n.getText("plugin.license.storage.admin.license.attribute.expirationdate.title")</td>
+                            <td>$license.get().expiryDate.get().toString($dateFormat)</td>
+                        </tr>
+                        #end
+                        #if ($license.maintenanceExpiryDate.isDefined())
+                        <tr>
+                            <td>$i18n.getText("plugin.license.storage.admin.license.attribute.maintenanceexpirationdate.title")</td>
+                            <td>$license.get().maintenanceExpiryDate.get().toString($dateFormat)</td>
+                        </tr>
+                        #end
+                        <tr>
+                            <td>$i18n.getText("plugin.license.storage.admin.license.attribute.description.title")</td>
+                            <td>$license.get().description</td>
+                        </tr>
+                        <tr>
+                            <td>$i18n.getText("plugin.license.storage.admin.license.attribute.organization.title")</td>
+                            <td>$license.get().organization.name</td>
+                        </tr>
+                        <tr>
+                            <td>$i18n.getText("plugin.license.storage.admin.license.attribute.serverid.title")</td>
+                            <td>$license.get().serverId</td>
+                        </tr>
+                        <tr>
+                            <td>$i18n.getText("plugin.license.storage.admin.license.attribute.sen.title")</td>
+                            #if ($license.get().supportEntitlementNumber.isDefined())
+                            <td>$license.get().supportEntitlementNumber</td>
+                            #end
+                        </tr>
+                    #end
+                </tbody>
+            </table>
+
+        <h4>$i18n.getText("plugin.license.storage.admin.license.action.update.title")</h4>
+
+        #if ($eligibleButtons)
+        <h6>$i18n.getText("plugin.license.storage.admin.license.action.acquire.title")</h6>
+        <table>
+            <tbody>
+            <tr>
+                #if ($buyPluginUri)
+                <td>
+                    <form action="$buyPluginUri" method="post" class="aui">
+                        <input class="button" type="submit" value="$i18n.getText("plugin.license.storage.admin.license.action.buy")">
+                    </form>
+                </td>
+                #end
+                #if ($tryPluginUri)
+                <td>
+                    <form action="$tryPluginUri" method="post" class="aui">
+                        <input class="button" type="submit" value="$i18n.getText("plugin.license.storage.admin.license.action.try")">
+                    </form>
+                </td>
+                #end
+                #if ($renewPluginUri)
+                <td>
+                    <form action="$renewPluginUri" method="post" class="aui">
+                        <input class="button" type="submit" value="$i18n.getText("plugin.license.storage.admin.license.action.renew")">
+                    </form>
+                </td>
+                #end
+                #if ($upgradePluginUri)
+                <td>
+                    <form action="$upgradePluginUri" method="post" class="aui">
+                        <input class="button" type="submit" value="$i18n.getText("plugin.license.storage.admin.license.action.upgrade")">
+                    </form>
+                </td>
+                #end
+            </tr>
+            </tbody>
+        </table>
+        #end
+
+        <h6>$i18n.getText("plugin.license.storage.admin.license.action.new.title")</h6>
+        <form action="$servletUri" method="post">
+            <textarea name="license" cols="80" rows="10">#if ($license.isDefined())$license.get().getRawLicense()#end</textarea>
+            <input type="submit" value="$i18n.getText("plugin.license.storage.admin.license.action.update")">
+        </form>
+        #end
+	</body>
+</html>