diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/InitializrService.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/InitializrService.java index ed4606e1bd..9c0d1aa34d 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/InitializrService.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/InitializrService.java @@ -48,6 +48,19 @@ class InitializrService { private static final Charset UTF_8 = Charset.forName("UTF-8"); + /** + * Accept header to use to retrieve the json meta-data. + */ + public static final String ACCEPT_META_DATA = + "application/vnd.initializr.v2.1+json,application/vnd.initializr.v2+json"; + + /** + * Accept header to use to retrieve the service capabilities of the service. If the + * service does not offer such feature, the json meta-data are retrieved instead. + */ + public static final String ACCEPT_SERVICE_CAPABILITIES = + "text/plain," + ACCEPT_META_DATA; + /** * Late binding HTTP client. */ @@ -80,12 +93,7 @@ class InitializrService { URI url = request.generateUrl(metadata); CloseableHttpResponse httpResponse = executeProjectGenerationRequest(url); HttpEntity httpEntity = httpResponse.getEntity(); - if (httpEntity == null) { - throw new ReportableException("No content received from server '" + url + "'"); - } - if (httpResponse.getStatusLine().getStatusCode() != 200) { - throw createException(request.getServiceUrl(), httpResponse); - } + validateResponse(httpResponse, request.getServiceUrl()); return createResponse(httpResponse, httpEntity); } @@ -97,6 +105,42 @@ class InitializrService { */ public InitializrServiceMetadata loadMetadata(String serviceUrl) throws IOException { CloseableHttpResponse httpResponse = executeInitializrMetadataRetrieval(serviceUrl); + validateResponse(httpResponse, serviceUrl); + return parseJsonMetadata(httpResponse.getEntity()); + } + + /** + * Loads the service capabilities of the service at the specified url. + *
If the service supports generating a textual representation of the
+ * capabilities, it is returned. Otherwhise the json meta-data as a
+ * {@link JSONObject} is returned.
+ * @param serviceUrl to url of the initializer service
+ * @return the service capabilities (as a String) or the metadata describing the service
+ * @throws IOException if the service capabilities cannot be loaded
+ */
+ public Object loadServiceCapabilities(String serviceUrl) throws IOException {
+ CloseableHttpResponse httpResponse = executeServiceCapabilitiesRetrieval(serviceUrl);
+ validateResponse(httpResponse, serviceUrl);
+ HttpEntity httpEntity = httpResponse.getEntity();
+ ContentType contentType = ContentType.getOrDefault(httpEntity);
+ if (contentType.getMimeType().equals("text/plain")) {
+ return getContent(httpEntity);
+ } else {
+ return parseJsonMetadata(httpEntity);
+ }
+ }
+
+ private InitializrServiceMetadata parseJsonMetadata(HttpEntity httpEntity) throws IOException {
+ try {
+ return new InitializrServiceMetadata(getContentAsJson(httpEntity));
+ }
+ catch (JSONException ex) {
+ throw new ReportableException("Invalid content received from server ("
+ + ex.getMessage() + ")", ex);
+ }
+ }
+
+ private void validateResponse(CloseableHttpResponse httpResponse, String serviceUrl) {
if (httpResponse.getEntity() == null) {
throw new ReportableException("No content received from server '"
+ serviceUrl + "'");
@@ -104,14 +148,6 @@ class InitializrService {
if (httpResponse.getStatusLine().getStatusCode() != 200) {
throw createException(serviceUrl, httpResponse);
}
- try {
- HttpEntity httpEntity = httpResponse.getEntity();
- return new InitializrServiceMetadata(getContentAsJson(httpEntity));
- }
- catch (JSONException ex) {
- throw new ReportableException("Invalid content received from server ("
- + ex.getMessage() + ")", ex);
- }
}
private ProjectGenerationResponse createResponse(CloseableHttpResponse httpResponse,
@@ -139,11 +175,19 @@ class InitializrService {
*/
private CloseableHttpResponse executeInitializrMetadataRetrieval(String url) {
HttpGet request = new HttpGet(url);
- request.setHeader(new BasicHeader(HttpHeaders.ACCEPT,
- "application/vnd.initializr.v2+json"));
+ request.setHeader(new BasicHeader(HttpHeaders.ACCEPT, ACCEPT_META_DATA));
return execute(request, url, "retrieve metadata");
}
+ /**
+ * Retrieves the service capabilities of the service at the specified URL
+ */
+ private CloseableHttpResponse executeServiceCapabilitiesRetrieval(String url) {
+ HttpGet request = new HttpGet(url);
+ request.setHeader(new BasicHeader(HttpHeaders.ACCEPT, ACCEPT_SERVICE_CAPABILITIES));
+ return execute(request, url, "retrieve help");
+ }
+
private CloseableHttpResponse execute(HttpUriRequest request, Object url,
String description) {
try {
@@ -188,11 +232,15 @@ class InitializrService {
}
private JSONObject getContentAsJson(HttpEntity entity) throws IOException {
+ return new JSONObject(getContent(entity));
+ }
+
+ private String getContent(HttpEntity entity) throws IOException {
ContentType contentType = ContentType.getOrDefault(entity);
Charset charset = contentType.getCharset();
charset = (charset != null ? charset : UTF_8);
byte[] content = FileCopyUtils.copyToByteArray(entity.getContent());
- return new JSONObject(new String(content, charset));
+ return new String(content, charset);
}
private String extractFileName(Header header) {
diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ServiceCapabilitiesReportGenerator.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ServiceCapabilitiesReportGenerator.java
index 885722ae44..02e2f52ee7 100644
--- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ServiceCapabilitiesReportGenerator.java
+++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ServiceCapabilitiesReportGenerator.java
@@ -54,7 +54,15 @@ class ServiceCapabilitiesReportGenerator {
* @throws IOException if the report cannot be generated
*/
public String generate(String url) throws IOException {
- InitializrServiceMetadata metadata = this.initializrService.loadMetadata(url);
+ Object content = this.initializrService.loadServiceCapabilities(url);
+ if (content instanceof InitializrServiceMetadata) {
+ return generateHelp(url, (InitializrServiceMetadata) content);
+ } else {
+ return content.toString();
+ }
+ }
+
+ private String generateHelp(String url, InitializrServiceMetadata metadata) {
String header = "Capabilities of " + url;
StringBuilder report = new StringBuilder();
report.append(StringUtils.repeat("=", header.length()) + NEW_LINE);
diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/AbstractHttpClientMockTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/AbstractHttpClientMockTests.java
index 180e90f4d3..8731e0a109 100644
--- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/AbstractHttpClientMockTests.java
+++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/AbstractHttpClientMockTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2014 the original author or authors.
+ * Copyright 2012-2015 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.
@@ -48,37 +48,51 @@ public abstract class AbstractHttpClientMockTests {
protected final CloseableHttpClient http = mock(CloseableHttpClient.class);
- protected void mockSuccessfulMetadataGet() throws IOException {
- mockSuccessfulMetadataGet("2.0.0");
+ protected void mockSuccessfulMetadataTextGet() throws IOException {
+ mockSuccessfulMetadataGet("metadata/service-metadata-2.1.0.txt", "text/plain", true);
}
- protected void mockSuccessfulMetadataGet(String version) throws IOException {
+ protected void mockSuccessfulMetadataGet(boolean serviceCapabilities) throws IOException {
+ mockSuccessfulMetadataGet("metadata/service-metadata-2.1.0.json",
+ "application/vnd.initializr.v2.1+json", serviceCapabilities);
+ }
+
+ protected void mockSuccessfulMetadataGetV2(boolean serviceCapabilities) throws IOException {
+ mockSuccessfulMetadataGet("metadata/service-metadata-2.0.0.json",
+ "application/vnd.initializr.v2+json", serviceCapabilities);
+ }
+
+ protected void mockSuccessfulMetadataGet(String contentPath, String contentType,
+ boolean serviceCapabilities) throws IOException {
CloseableHttpResponse response = mock(CloseableHttpResponse.class);
- Resource resource = new ClassPathResource("metadata/service-metadata-" + version
- + ".json");
- byte[] content = StreamUtils.copyToByteArray(resource.getInputStream());
- mockHttpEntity(response, content, "application/vnd.initializr.v2+json");
+ byte[] content = readClasspathResource(contentPath);
+ mockHttpEntity(response, content, contentType);
mockStatus(response, 200);
- given(this.http.execute(argThat(getForJsonMetadata()))).willReturn(response);
+ given(this.http.execute(argThat(getForMetadata(serviceCapabilities)))).willReturn(response);
+ }
+
+ protected byte[] readClasspathResource(String contentPath) throws IOException {
+ Resource resource = new ClassPathResource(contentPath);
+ return StreamUtils.copyToByteArray(resource.getInputStream());
}
protected void mockSuccessfulProjectGeneration(
MockHttpProjectGenerationRequest request) throws IOException {
// Required for project generation as the metadata is read first
- mockSuccessfulMetadataGet();
+ mockSuccessfulMetadataGet(false);
CloseableHttpResponse response = mock(CloseableHttpResponse.class);
mockHttpEntity(response, request.content, request.contentType);
mockStatus(response, 200);
String header = (request.fileName != null ? contentDispositionValue(request.fileName)
: null);
mockHttpHeader(response, "Content-Disposition", header);
- given(this.http.execute(argThat(getForNonJsonMetadata()))).willReturn(response);
+ given(this.http.execute(argThat(getForNonMetadata()))).willReturn(response);
}
protected void mockProjectGenerationError(int status, String message)
throws IOException {
// Required for project generation as the metadata is read first
- mockSuccessfulMetadataGet();
+ mockSuccessfulMetadataGet(false);
CloseableHttpResponse response = mock(CloseableHttpResponse.class);
mockHttpEntity(response, createJsonError(status, message).getBytes(),
"application/json");
@@ -122,12 +136,17 @@ public abstract class AbstractHttpClientMockTests {
given(response.getFirstHeader(headerName)).willReturn(header);
}
- protected Matcher