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}