/src/main/java/com/atlassian/jconnect/jira/tabpanel/AbstractChartFragment.java
Java | 213 lines | 161 code | 30 blank | 22 comment | 12 complexity | 4e0bb9e354b4eb4665e5dbb87e84110f MD5 | raw file
- package com.atlassian.jconnect.jira.tabpanel;
- import com.atlassian.jconnect.jira.IssueHelper;
- import com.atlassian.jira.bc.issue.search.SearchService;
- import com.atlassian.jira.charts.jfreechart.ChartHelper;
- import com.atlassian.jira.config.properties.ApplicationProperties;
- import com.atlassian.jira.issue.Issue;
- import com.atlassian.jira.issue.search.SearchException;
- import com.atlassian.jira.issue.search.SearchResults;
- import com.atlassian.jira.plugin.projectpanel.fragment.impl.AbstractFragment;
- import com.atlassian.jira.project.browse.BrowseContext;
- import com.atlassian.jira.security.JiraAuthenticationContext;
- import com.atlassian.jira.util.ErrorCollection;
- import com.atlassian.jira.util.SimpleErrorCollection;
- import com.atlassian.jira.web.bean.PagerFilter;
- import com.atlassian.velocity.VelocityManager;
- import org.apache.commons.lang.StringUtils;
- import org.jfree.chart.ChartFactory;
- import org.jfree.chart.JFreeChart;
- import org.jfree.chart.axis.NumberAxis;
- import org.jfree.chart.plot.PlotOrientation;
- import org.jfree.chart.renderer.category.BarRenderer;
- import org.jfree.data.category.CategoryDataset;
- import org.jfree.data.category.DefaultCategoryDataset;
- import java.awt.*;
- import java.util.Collections;
- import java.util.List;
- import java.util.Map;
- import java.util.regex.Matcher;
- /**
- * Base class for generating issue breakdown charts by data from environment field.
- *
- */
- public abstract class AbstractChartFragment extends AbstractFragment {
- protected static final int WIDTH = com.atlassian.jira.charts.ChartFactory.FRAGMENT_IMAGE_WIDTH;
- protected static final int HEIGHT = com.atlassian.jira.charts.ChartFactory.FRAGMENT_IMAGE_HEIGHT;
- private static final Color NICE_BLUE = new Color(51 , 102, 204);
- private static final Color NICE_RED = new Color(220, 57, 18);
- private static final Color NICE_YELLOW = new Color(255, 153, 0);
- private static final Color NICE_GREEN = new Color(16, 150, 24);
- private static final Color NICE_VIOLET = new Color(153, 0, 153);
- private static final Color[] BAR_COLORS = {
- NICE_BLUE,
- NICE_RED,
- NICE_YELLOW,
- NICE_GREEN,
- NICE_VIOLET
- };
- protected final SearchService searchService;
- public AbstractChartFragment(SearchService searchService, VelocityManager velocityManager,
- ApplicationProperties applicationProperites,
- JiraAuthenticationContext jiraAuthenticationContext) {
- super(velocityManager, applicationProperites, jiraAuthenticationContext);
- this.searchService = searchService;
- }
- // final is quite strict but as of now we don't see any modification you would apply here, and if somebody overrides
- // this template method, half of this class is rendered useless so you may as well not extend it at all!
- // i.e. think about how to hook into this instead of overriding!
- @Override
- protected final Map<String, Object> createVelocityParams(BrowseContext ctx) {
- final Map<String, Object> params = super.createVelocityParams(ctx);
- final ErrorCollection errors = new SimpleErrorCollection();
- final List<Issue> issues = collectIssues(ctx, errors);
- generateChart(params, issues, errors);
- params.put("errors", errors);
- return params;
- }
- private List<Issue> collectIssues(BrowseContext ctx, ErrorCollection errors) {
- final String jql = "project=" + ctx.getProject().getKey() + " order by createdDate";
- SearchService.ParseResult parseResult = searchService.parseQuery(jiraAuthenticationContext.getLoggedInUser(), jql);
- if (!parseResult.isValid()) {
- errors.addErrorMessages(parseResult.getErrors().getErrorMessages());
- } else {
- try {
- final SearchResults results = searchService.search(jiraAuthenticationContext.getLoggedInUser(),
- parseResult.getQuery(), PagerFilter.newPageAlignedFilter(0, 500));
- return results.getIssues();
- } catch (SearchException se) {
- errors.addErrorMessage(se.getLocalizedMessage());
- }
- }
- return Collections.emptyList();
- }
- protected CategoryDataset createDataset(List<Issue> issues) {
- final DefaultCategoryDataset answer = new DefaultCategoryDataset();
- for (Issue issue : issues) {
- String fieldValue = parseEnvironmentString(issue.getEnvironment());
- if (fieldValue == null) {
- continue; // ignore...
- }
- fieldValue = fieldValue.trim();
- if (!answer.getColumnKeys().contains(fieldValue)) {
- answer.addValue(0, issueCountName(), fieldValue);
- }
- answer.incrementValue(1, issueCountName(), fieldValue);
- }
- return answer;
- }
- protected void generateChart(Map<String, Object> params, List<Issue> issues, ErrorCollection errors) {
- if (issues.isEmpty()) {
- return;
- }
- try {
- final CategoryDataset dataset = createDataset(issues);
- JFreeChart chart = ChartFactory.createBarChart(
- null,
- getText(i18nPrefix() + ".xaxistitle"),
- issueCountName(),
- dataset,
- PlotOrientation.VERTICAL,
- false,
- true,
- false
- );
- chart.getCategoryPlot().setRenderer(new CustomBarColorsRenderer(BAR_COLORS));
- chart.setBackgroundPaint(Color.white);
- chart.getCategoryPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits());
- ChartHelper chartHelper = new ChartHelper(chart);
- chartHelper.generate(WIDTH, HEIGHT);
- params.put("chart", chartHelper.getLocation());
- params.put("imagemap", chartHelper.getImageMap());
- params.put("imagemapName", chartHelper.getImageMapName());
- params.put("imageWidth", WIDTH);
- params.put("imageHeight", HEIGHT);
- } catch (Exception e) {
- log.error("Error while creating chart", e);
- errors.addErrorMessage(jiraAuthenticationContext.getI18nHelper().getText(
- i18nPrefix() + ".charterror", e.getMessage()));
- }
- }
- /**
- * Matcher group number for regex-parsing the environment field.
- *
- * @return matcher group number
- * @see IssueHelper#ENV_FIELD_PATTERN
- */
- public abstract int groupNumber();
- /**
- * I18n prefix to get standard text resources.
- *
- * @return i18n prefix
- */
- public String i18nPrefix() {
- return JiraConnectProjectTabPanel.I18N_PREFIX + "." + getId();
- }
- protected String parseEnvironmentString(String environment) {
- if (environment == null || StringUtils.isEmpty(environment)) {
- return null;
- }
- Matcher matcher = IssueHelper.ENV_FIELD_PATTERN.matcher(environment);
- if (matcher.find()) {
- return matcher.group(groupNumber());
- } else {
- return getText(i18nPrefix() + ".unknown");
- }
- }
- protected final String getText(String key) {
- return jiraAuthenticationContext.getI18nHelper().getText(key);
- }
- public final String issueCountName() {
- return getText(i18nPrefix() + ".yaxistitle");
- }
- @Override
- protected final String getTemplateDirectoryPath() {
- return JiraConnectProjectTabPanel.TEMPLATE_DIR;
- }
- public boolean showFragment(BrowseContext browseContext) {
- // show by default
- return true;
- }
- /**
- * A custom renderer that returns a different color for each bar in a single series.
- */
- private static class CustomBarColorsRenderer extends BarRenderer {
- private final Paint[] colors;
- public CustomBarColorsRenderer(final Paint[] colors) {
- this.colors = colors;
- }
- @Override
- public Paint getItemPaint(final int row, final int column) {
- return this.colors[column % this.colors.length];
- }
- }
- }