/******************************************************************************* * Copyright (c) 2017 IBM Corp. * * 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 com.ibm.liberty.starter.client; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import javax.json.Json; import javax.json.JsonObject; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import com.ibm.liberty.starter.ProjectConstructionInputData; import com.ibm.liberty.starter.exception.ProjectGenerationException; public class BxCodegenClient { private static final Logger log = Logger.getLogger(BxCodegenClient.class.getName()); public final String URL = System.getenv("bxCodegenEndpoint"); public final String STARTERKIT_URL = System.getenv("appAccelStarterkit"); private final int retriesAllowed = 18; public Map<String, byte[]> getFileMap(ProjectConstructionInputData inputData) throws ProjectGenerationException { checkConfig(); if (inputData.generationId != null) { return getExistingFileMap(inputData.generationId); } else { return generateAndGetFileMap(inputData); } } private Map<String, byte[]> generateAndGetFileMap(ProjectConstructionInputData inputData) { String payload = getPayload(inputData); String id = callBxCodegen(payload); waitForFinishedStatus(id); Map<String, byte[]> projectMap = getProjectMap(id); return projectMap; } private Map<String, byte[]> getExistingFileMap(String id) { Map<String, byte[]> projectMap = getProjectMap(id); return projectMap; } public String generateProject(ProjectConstructionInputData inputData) throws ProjectGenerationException { checkConfig(); String payload = getPayload(inputData); String id = callBxCodegen(payload); waitForFinishedStatus(id); return id; } private void checkConfig() throws ProjectGenerationException { String missingConfig = ""; if(URL == null) { missingConfig += "generation URL, "; } if (STARTERKIT_URL == null) { missingConfig += "starter URL, "; } if (!missingConfig.isEmpty()) { String missing = missingConfig.substring(0, missingConfig.length() - 1); throw new ProjectGenerationException("Missing project generation configuration: " + missing); } } private String getPayload(ProjectConstructionInputData inputData) { String payload = "{\"project\":{" + "\"backendPlatform\":\"JAVA\"," + "\"name\":\"" + inputData.appName + "\"}," + "\"generatorOptions\":{" + "\"generator-ibm-java\":{" + "\"options\":" + inputData.toBxJSON() + "}}," + "\"templateSources\":[\"" + STARTERKIT_URL + "\"]}"; return payload; } protected String callBxCodegen(String payload) { System.out.println("Sending codegen request with payload: " + payload); Client client = ClientBuilder.newClient(); WebTarget target = client.target(URL + "api/generator"); Invocation.Builder invoBuild = target.request(); Response response = invoBuild.accept(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(payload)); String responseString = response.readEntity(String.class); responseString.replaceAll(" ", ""); InputStream is = new ByteArrayInputStream(responseString.getBytes()); JsonObject object = Json.createReader(is).readObject(); JsonObject job = (JsonObject) object.get("job"); String id = job.getString("id"); System.out.println("Received job id: " + id); return id; } private void waitForFinishedStatus(String id) throws ProjectGenerationException { int retries = 0; while (("RUNNING").equals(checkStatus(id)) && retries <= retriesAllowed) { System.out.println("Retry number " + retries); try { Thread.sleep(3000); } catch (InterruptedException e) { log.severe(e.getClass().getName() + " caught " + e.getMessage()); throw new ProjectGenerationException("Code generation failed for job with id: " + id + ". Try again later."); } retries++; } String status = checkStatus(id); if(!("FINISHED").equals(status)) { if ("FAILED".equals(status)) { throw new ProjectGenerationException("Code generation failed for job with id: " + id + ". Try again later."); } if ("RUNNING".equals(status)) { throw new ProjectGenerationException("Code generation for job with id " + id + " timed out. Try again later"); } throw new ProjectGenerationException("Did not receive FINISHED from Bx codegen for job with id: " + id + ". Status received:" + status); } } protected String checkStatus(String id) { Client client = ClientBuilder.newClient(); WebTarget target = client.target(URL + "api/generator/" + id + "/status"); Invocation.Builder invoBuild = target.request(); Response response = invoBuild.accept(MediaType.APPLICATION_JSON_TYPE).get(); JsonObject responseObject = response.readEntity(JsonObject.class); String responseStatus = responseObject.getString("status"); System.out.println("Received response status : " + responseStatus); return responseStatus; } protected Map<String, byte[]> getProjectMap(String id) { Client client = ClientBuilder.newClient(); WebTarget target = client.target(URL + "api/generator/" + id); Invocation.Builder invoBuild = target.request(); Response response = invoBuild.accept("application/zip").get(); InputStream is= response.readEntity(InputStream.class); ZipInputStream zis = new ZipInputStream(is); Map<String, byte[]> map = new HashMap<String, byte[]>(); ZipEntry ze; try { while ((ze = zis.getNextEntry()) != null) { String path = ze.getName(); int length = 0; byte[] bytes = new byte[1024]; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while ((length = zis.read(bytes)) != -1 ) { baos.write(bytes, 0, length); } map.put(path, baos.toByteArray()); } zis.close(); } catch (IOException e) { log.severe("Caught IOException while reading project zip to Map<String, byte[]> : " + e.getMessage()); throw new ProjectGenerationException("Code generation failed for job with id: " + id + ". Try again later."); } return map; } }