sagan.projects.support.VersionBadgeService.java Source code

Java tutorial

Introduction

Here is the source code for sagan.projects.support.VersionBadgeService.java

Source

/*
 * Copyright 2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sagan.projects.support;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.xmlbeam.XBProjector;
import org.xmlbeam.XBProjector.Flags;
import org.xmlbeam.config.DefaultXMLFactoriesConfig;
import org.xmlbeam.config.DefaultXMLFactoriesConfig.NamespacePhilosophy;

import sagan.projects.Project;
import sagan.projects.ProjectRelease;
import sagan.projects.ProjectRelease.ReleaseStatus;
import sagan.projects.support.BadgeSvg.GraphicElement;
import sagan.projects.support.BadgeSvg.Path;

import com.google.common.io.Resources;

/**
 * Service to generate SVG badges.
 *
 * @author Mark Paluch
 */
@Service
public class VersionBadgeService {

    private final URL PRERELEASE_TEMPLATE = Resources.getResource("badge/milestone.svg");
    private final URL GENERAL_AVAILABILITY_TEMPLATE = Resources.getResource("badge/release.svg");
    private final URL SNAPSHOT_TEMPLATE = Resources.getResource("badge/snapshot.svg");
    private final URL VERDANA_FONT = Resources.getResource("badge/Verdana.ttf");
    private final BufferedImage DUMMY = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
    private Graphics graphics;
    private XBProjector xbProjector;

    @PostConstruct
    public void postConstruct() throws Exception {

        Font font;
        try (InputStream is = VERDANA_FONT.openStream()) {
            font = Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(0, 11);
        }

        graphics = DUMMY.getGraphics();
        graphics.setFont(font);

        DefaultXMLFactoriesConfig myConfig = new DefaultXMLFactoriesConfig();
        myConfig.setNamespacePhilosophy(NamespacePhilosophy.NIHILISTIC);

        xbProjector = new XBProjector(myConfig, Flags.TO_STRING_RENDERS_XML);
    }

    @PreDestroy
    public void preDestroy() {
        graphics.dispose();
    }

    /**
     * Create a version badge for a given {@link Project} and {@link ProjectRelease}. The badge uses SVG and is returned as byte
     * array.
     *
     * @param project must not be {@literal null}.
     * @param projectRelease must not be {@literal null}.
     * @return
     * @throws IOException
     */
    public byte[] createSvgBadge(Project project, ProjectRelease projectRelease) throws IOException {

        Assert.notNull(project, "Project must not be null!");
        Assert.notNull(projectRelease, "ProjectRelease must not be null!");

        URL template = getTemplate(projectRelease.getReleaseStatus());

        BadgeSvg svgDocument = xbProjector.io().url(template.toString()).read(BadgeSvg.class);

        List<Path> paths = svgDocument.getPaths();

        String label = project.getName();
        String version = projectRelease.getVersion();

        return createSvgBadge(svgDocument, paths, label, version);
    }

    private byte[] createSvgBadge(BadgeSvg svgDocument, List<Path> paths, String label, String version) {

        List<GraphicElement> graphicElements = svgDocument.getGraphicElements();
        graphicElements.get(0).setText(label);
        graphicElements.get(1).setText(label);

        graphicElements.get(2).setText(version);
        graphicElements.get(3).setText(version);

        int labelMarginLeft = 6;
        int labelMarginRight = 4;

        int versionMarginLeft = 4;
        int versionMarginRight = 6;

        int labelTextWidth;
        int versionTextWidth;

        synchronized (graphics) {
            FontMetrics fontMetrics = graphics.getFontMetrics();
            labelTextWidth = fontMetrics.stringWidth(label);
            versionTextWidth = fontMetrics.stringWidth(version);
        }

        int labelWidth = labelTextWidth + labelMarginLeft + labelMarginRight;
        int versionWidth = versionTextWidth + versionMarginLeft + versionMarginRight;

        svgDocument.setWidth(labelWidth + versionWidth);
        svgDocument.getMask().setWidth(labelWidth + versionWidth);

        graphicElements.get(0).setXPosition(labelMarginLeft + (labelTextWidth / 2));
        graphicElements.get(1).setXPosition(labelMarginLeft + (labelTextWidth / 2));

        graphicElements.get(2).setXPosition(labelWidth + versionMarginLeft + (versionTextWidth / 2));
        graphicElements.get(3).setXPosition(labelWidth + versionMarginLeft + (versionTextWidth / 2));

        paths.get(0).setDraw(String.format("M0 0h%dv20H0z", labelWidth));
        paths.get(1).setDraw(String.format("M%d 0h%dv20H%dz", labelWidth, versionWidth, labelWidth));
        paths.get(2).setDraw(String.format("M0 0h%dv20H0z", labelWidth + versionWidth));

        return svgDocument.toString().getBytes();
    }

    private URL getTemplate(ReleaseStatus releaseStatus) {

        switch (releaseStatus) {
        case GENERAL_AVAILABILITY:
            return GENERAL_AVAILABILITY_TEMPLATE;
        case PRERELEASE:
            return PRERELEASE_TEMPLATE;
        default:
            return SNAPSHOT_TEMPLATE;
        }
    }
}