001package com.credibledoc.substitution.doc.module.substitution.pom;
002
003import com.credibledoc.substitution.core.content.Content;
004import com.credibledoc.substitution.core.content.ContentGenerator;
005import com.credibledoc.substitution.core.exception.SubstitutionRuntimeException;
006import com.credibledoc.substitution.core.placeholder.Placeholder;
007import lombok.RequiredArgsConstructor;
008import lombok.extern.slf4j.Slf4j;
009import org.springframework.stereotype.Service;
010
011import javax.inject.Inject;
012import java.io.InputStream;
013import java.net.HttpURLConnection;
014import java.net.URL;
015
016/**
017 * Generates the published jar name. Tries to find out the LATEST version in a Nexus repository, for example from
018 * the
019 * <a href="https://repo1.maven.org/maven2/com/credibledoc/plantuml-core/maven-metadata.xml">plantuml-core</a>
020 * API url. If the LATEST version not found, the {@link #NOT_PUBLISHED_YET} string will be returned.
021 * <p>
022 * Link to the repository API is defined in the <i>url</i> {@link Placeholder#getParameters()} property.
023 * <p>
024 * Example
025 * <pre>
026 *     &&beginPlaceholder {
027 *             "className": "com.credibledoc.substitution.doc.module.substitution.pom.JarNameContentGenerator",
028 *             "description": "Latest plantuml-core.jar name",
029 *             "parameters": {"url": "https://repo1.maven.org/maven2/com/credibledoc/plantuml-core/maven-metadata.xml"}
030 *           } &&endPlaceholder
031 * </pre>
032 *
033 * @author Kyrylo Semenko
034 */
035@Service
036@RequiredArgsConstructor(onConstructor = @__(@Inject))
037@Slf4j
038public class JarNameContentGenerator implements ContentGenerator {
039
040    private static final String NOT_PUBLISHED_YET = "'The artifact not published yet.'";
041    private static final String TEXT_XML = "text/xml";
042    private static final String ARTIFACT_ID_BEGIN_TAG = "<artifactId>";
043    private static final String ARTIFACT_ID_END_TAG = "</artifactId>";
044    private static final String LATEST_BEGIN_TAG = "<latest>";
045    private static final String LATEST_END_TAG = "</latest>";
046
047    @Override
048    public Content generate(Placeholder placeholder) {
049        String url = placeholder.getParameters().get("url");
050        if (url == null) {
051            throw new SubstitutionRuntimeException("Placeholder parameter 'url' is required, but found 'null'.");
052        }
053        return loadJarName(url);
054    }
055
056    private Content loadJarName(String urlParameter) {
057        String result;
058        try {
059            URL url = new URL(urlParameter);
060            HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
061            int responseCode = httpConn.getResponseCode();
062            if (responseCode == HttpURLConnection.HTTP_OK) {
063                String contentType = httpConn.getContentType();
064                if (!TEXT_XML.equals(contentType)) {
065                    throw new SubstitutionRuntimeException("Expected '" + TEXT_XML + "', but found " + contentType);
066                }
067                InputStream inputStream = httpConn.getInputStream();
068                String xmlString = convertStreamToString(inputStream);
069                String artifactId = parseTag(xmlString, ARTIFACT_ID_BEGIN_TAG, ARTIFACT_ID_END_TAG);
070                String latestVersion = parseTag(xmlString, LATEST_BEGIN_TAG, LATEST_END_TAG);
071                result = artifactId + "-" + latestVersion + ".jar";
072            } else {
073                log.info("ResponseCode is " + responseCode);
074                result = NOT_PUBLISHED_YET;
075            }
076            httpConn.disconnect();
077        } catch (Exception e) {
078            throw new SubstitutionRuntimeException(e);
079        }
080        Content content = new Content();
081        content.setMarkdownContent(result);
082        return content;
083    }
084
085    private String parseTag(String xmlString, String beginTag, String endTag) {
086        int beginIndex = xmlString.indexOf(beginTag);
087        if (beginIndex == -1) {
088            throw new SubstitutionRuntimeException("Cannot find " + beginTag);
089        }
090        int endIndex = xmlString.indexOf(endTag, beginIndex);
091        if (endIndex == -1) {
092            throw new SubstitutionRuntimeException("Cannot find " + endTag);
093        }
094        return xmlString.substring(beginIndex + beginTag.length(), endIndex);
095    }
096
097    private String convertStreamToString(InputStream is) {
098        java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
099        return s.hasNext() ? s.next() : "";
100    }
101}