Java tutorial
package com.atlassian.jira.plugin.aboutpagepanel; import java.io.IOException; import java.io.InputStream; import java.io.Writer; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; import com.atlassian.jira.config.util.EncodingConfiguration; import com.atlassian.jira.license.thirdparty.BomParser; import com.atlassian.jira.plugin.webfragment.descriptors.JiraAbstractWebFragmentModuleDescriptor; import com.atlassian.jira.security.JiraAuthenticationContext; import com.atlassian.jira.template.soy.SoyTemplateRendererProvider; import com.atlassian.plugin.Plugin; import com.atlassian.plugin.PluginParseException; import com.atlassian.plugin.web.WebInterfaceManager; import com.atlassian.plugin.web.descriptors.DefaultWebItemModuleDescriptor; import com.atlassian.soy.renderer.SoyException; import com.atlassian.soy.renderer.SoyTemplateRenderer; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.dom4j.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.apache.commons.lang.StringUtils.isEmpty; public class AboutPagePanelModuleDescriptorImpl extends JiraAbstractWebFragmentModuleDescriptor implements AboutPagePanelModuleDescriptor { private static final Logger log = LoggerFactory.getLogger(AboutPagePanelModuleDescriptorImpl.class); private static final String LOCATION_KEY = "location"; private static final String MODULE_KEY = "module-key"; private static final String FUNCTION_KEY = "function"; private final EncodingConfiguration encodingConfiguration; private final SoyTemplateRendererProvider soyTemplateRendererProvider; private final BomParser bomParser; private volatile String introduction = ""; private volatile String licenses = ""; private volatile String conclusion = ""; private volatile String introductionModule = ""; private volatile String conclusionModule = ""; public AboutPagePanelModuleDescriptorImpl(JiraAuthenticationContext jiraAuthenticationContext, final WebInterfaceManager webInterfaceManager, final EncodingConfiguration encodingConfiguration, final SoyTemplateRendererProvider soyTemplateRendererProvider, final BomParser bomParser) { super(jiraAuthenticationContext, new DefaultWebItemModuleDescriptor(webInterfaceManager)); this.encodingConfiguration = encodingConfiguration; this.soyTemplateRendererProvider = soyTemplateRendererProvider; this.bomParser = bomParser; } @Override public void init(final Plugin plugin, final Element element) throws PluginParseException { super.init(plugin, element); Element introduction = element.element("introduction"); Element licenses = element.element("licenses"); Element conclusion = element.element("conclusion"); if (introduction == null && licenses == null && conclusion == null) throw new PluginParseException( "An introduction template, licenses file or conclusion template must be provided."); if (introduction != null) { this.introduction = assertFunctionPresent(introduction, "Introduction"); this.introductionModule = assertModuleKeyPresent(introduction, "Introduction"); } if (licenses != null) { this.licenses = assertLocationPresent(licenses, "Licenses"); } if (conclusion != null) { this.conclusion = assertFunctionPresent(conclusion, "Conclusion"); this.conclusionModule = assertModuleKeyPresent(conclusion, "Conclusion"); } } private String assertModuleKeyPresent(final Element introduction, String field) { String location = introduction.attributeValue(MODULE_KEY); if (StringUtils.isEmpty(location)) throw new PluginParseException(field + " module key must be specified"); return location; } private String assertLocationPresent(final Element introduction, String field) { String location = introduction.attributeValue(LOCATION_KEY); if (StringUtils.isEmpty(location)) throw new PluginParseException(field + " license file must be specified"); return location; } private String assertFunctionPresent(final Element introduction, String field) { String location = introduction.attributeValue(FUNCTION_KEY); if (StringUtils.isEmpty(location)) throw new PluginParseException(field + " function must be specified"); return location; } @Override public String getPluginSectionHtml() { PluginAndMaterials pluginAndMaterials = getPluginAndMaterials(); if (pluginAndMaterials == null) return ""; HashMap<String, Object> a = Maps.newHashMap(); a.put("pluginEntry", pluginAndMaterials); try { return getSoyRenderer().render("jira.webresources:action-soy-templates", "JIRA.Templates.About.renderModule", a); } catch (SoyException e) { log.debug("Problem rendering {}", pluginAndMaterials, e); return ""; } } @Override public String getHtml(final String resourceName) { return getPluginSectionHtml(); } @Override public String getHtml(final String resourceName, final Map<String, ?> startingParams) { return getPluginSectionHtml(); } @Override public void writeHtml(final String resourceName, final Map<String, ?> startingParams, final Writer writer) throws IOException { writer.write(getPluginSectionHtml()); } private PluginAndMaterials getPluginAndMaterials() { final Plugin plugin = getPlugin(); try { SoyTemplateRenderer soyTemplateRenderer = getSoyRenderer(); List<Material> a = getMaterials(plugin); Map<String, Object> data = getContextProvider().getContextMap(Collections.<String, Object>emptyMap()); String introduction = generateIntroduction(soyTemplateRenderer, data); String conclusion = generateConclusion(soyTemplateRenderer, data); return new PluginAndMaterials(plugin.getName(), plugin.getPluginInformation().getVersion(), introduction, conclusion, a); } catch (RuntimeException e) { // Failure to load one plugin's information should not cause the about box to not be displayed. log.info("Could not load license information for " + plugin.getName() + " " + plugin.getKey(), e); } return null; } @VisibleForTesting List<Material> getMaterials(final Plugin plugin) { return Lists.newArrayList(loadMaterials(plugin)); } private Set<Material> loadMaterials(final Plugin plugin) { final Set<Material> materials = Sets.newTreeSet(); if (!isEmpty(this.getLicensesLocation())) { ClassLoader classLoader = plugin.getClassLoader(); InputStream resourceAsStream = classLoader.getResourceAsStream(this.getLicensesLocation()); if (resourceAsStream != null) { try { String bomContents = IOUtils.toString(resourceAsStream, encodingConfiguration.getEncoding()); Iterables.addAll(materials, bomParser.extractLgplMaterials(bomContents)); } catch (IOException e) { log.debug("Could not load detailed license information for " + plugin.getName() + " " + plugin.getKey() + " : " + this.getName() + " at " + this.getLicensesLocation(), e); } finally { IOUtils.closeQuietly(resourceAsStream); } } else { log.debug("Could not locate detailed license information for " + plugin.getName() + " " + plugin.getKey() + " : " + this.getName() + " at " + this.getLicensesLocation()); } } return materials; } @VisibleForTesting String generateIntroduction(SoyTemplateRenderer soyTemplateRenderer, Map<String, Object> data) { return introductionOk() ? renderItem(soyTemplateRenderer, introduction, getIntroductionModuleKey(), data) : ""; } @VisibleForTesting String generateConclusion(SoyTemplateRenderer soyTemplateRenderer, Map<String, Object> data) { return conclusionOk() ? renderItem(soyTemplateRenderer, conclusion, getConclusionModuleKey(), data) : ""; } private boolean introductionOk() { return !isEmpty(introduction) && !isEmpty(introductionModule); } private boolean conclusionOk() { return !isEmpty(conclusion) && !isEmpty(conclusionModule); } @VisibleForTesting String renderItem(final SoyTemplateRenderer soyTemplateRenderer, final String item, final String itemModuleKey, Map<String, Object> data) { try { return soyTemplateRenderer.render(itemModuleKey, item, data); } catch (SoyException e) { log.info("Couldn't render 'about-license' for " + itemModuleKey + ". Continuing with other modules.", e); } catch (RuntimeException e) { log.info("Couldn't render 'about-license' for " + itemModuleKey + ". Continuing with other modules.", e); } return ""; } private SoyTemplateRenderer getSoyRenderer() { return soyTemplateRendererProvider.getRenderer(); } public String getIntroductionModuleKey() { return introductionModule; } public String getLicensesLocation() { return licenses; } public String getConclusionModuleKey() { return conclusionModule; } /** * Ties a bill of materials in with its plugins */ public static final class PluginAndMaterials implements Comparable<PluginAndMaterials> { private final String pluginName; private final String pluginVersion; private final String introduction; private final String conclusion; private final List<Material> materials; public PluginAndMaterials(final String pluginName, final String pluginVersion, final String introduction, final String conclusion, final List<Material> materials) { this.pluginName = pluginName; this.pluginVersion = pluginVersion; this.introduction = introduction; this.conclusion = conclusion; this.materials = materials; } public String getPluginName() { return pluginName; } public String getPluginVersion() { return pluginVersion; } public String getIntroductionHtml() { return introduction; } public String getConclusionHtml() { return conclusion; } public List<Material> getMaterials() { return materials; } public boolean isEntries() { return materials != null && materials.size() > 0; } @Override public int compareTo(@Nonnull PluginAndMaterials pluginAndMaterials) { if (pluginAndMaterials == null) return 1; int compare = getPluginName().compareTo(pluginAndMaterials.getPluginName()); if (compare != 0) return compare; compare = getPluginVersion().compareTo(pluginAndMaterials.getPluginVersion()); if (compare != 0) return compare; compare = getIntroductionHtml().compareTo(pluginAndMaterials.getIntroductionHtml()); if (compare != 0) return compare; compare = getConclusionHtml().compareTo(pluginAndMaterials.getConclusionHtml()); if (compare != 0) return compare; return getMaterials().size() - pluginAndMaterials.getMaterials().size(); } } /** * Encapsulates data from the Bill Of Materials */ public static final class Material implements Comparable<Material> { private final String libraryName; private final String mavenInfo; private final String license; private final String url; private final String artifactType; public Material(final String libraryName, final String mavenInfo, final String license, final String url, final String artifactType) { this.libraryName = libraryName; this.mavenInfo = mavenInfo; this.license = license; this.url = url; this.artifactType = artifactType; } public String getLibraryName() { return libraryName == null ? "" : libraryName; } public String getMavenInfo() { return mavenInfo == null ? "" : mavenInfo; } public String getLicense() { return license == null ? "" : license; } public String getUrl() { return url == null ? "" : url; } public String getArtifactType() { return artifactType == null ? "" : artifactType; } public boolean isUrlAndGav() { return !(isEmpty(mavenInfo) || isEmpty(url)); } public boolean isUrlNotGav() { return isEmpty(mavenInfo) && !isEmpty(url); } public boolean isGavNotUrl() { return !isEmpty(mavenInfo) && isEmpty(url); } public String toString() { return getLibraryName() + "," + getMavenInfo() + "," + getLicense() + "," + getUrl() + "," + getArtifactType(); } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } final Material material = (Material) o; if (artifactType != null ? !artifactType.equals(material.artifactType) : material.artifactType != null) { return false; } if (libraryName != null ? !libraryName.equals(material.libraryName) : material.libraryName != null) { return false; } if (license != null ? !license.equals(material.license) : material.license != null) { return false; } if (mavenInfo != null ? !mavenInfo.equals(material.mavenInfo) : material.mavenInfo != null) { return false; } if (url != null ? !url.equals(material.url) : material.url != null) { return false; } return true; } @Override public int hashCode() { int result = libraryName != null ? libraryName.hashCode() : 0; result = 31 * result + (mavenInfo != null ? mavenInfo.hashCode() : 0); result = 31 * result + (license != null ? license.hashCode() : 0); result = 31 * result + (url != null ? url.hashCode() : 0); result = 31 * result + (artifactType != null ? artifactType.hashCode() : 0); return result; } @Override public int compareTo(@Nonnull final Material material) { int result = this.getLibraryName().compareTo(material.getLibraryName()); if (result != 0) { return result; } result = this.getMavenInfo().compareTo(material.getMavenInfo()); if (result != 0) { return result; } result = this.getLicense().compareTo(material.getLicense()); if (result != 0) { return result; } result = this.getUrl().compareTo(material.getUrl()); if (result != 0) { return result; } return this.getArtifactType().compareTo(material.getArtifactType()); } } }