package org.kie.server.integrationtests.controller.client;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.kie.server.api.marshalling.Marshaller;
import org.kie.server.api.marshalling.MarshallerFactory;
import org.kie.server.api.marshalling.MarshallingException;
import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.controller.api.model.KieServerInstance;
import org.kie.server.controller.api.model.KieServerInstanceInfo;
import org.kie.server.controller.api.model.KieServerInstanceList;
import org.kie.server.controller.api.model.KieServerSetup;
import org.kie.server.controller.api.model.KieServerStatus;
import org.kie.server.controller.api.model.runtime.Container;
import org.kie.server.controller.api.model.runtime.ContainerKey;
import org.kie.server.controller.api.model.runtime.ServerInstance;
import org.kie.server.controller.api.model.runtime.ServerInstanceKey;
import org.kie.server.controller.api.model.spec.Capability;
import org.kie.server.controller.api.model.spec.ContainerConfig;
import org.kie.server.controller.api.model.spec.ContainerSpec;
import org.kie.server.controller.api.model.spec.ContainerSpecKey;
import org.kie.server.controller.api.model.spec.ContainerSpecList;
import org.kie.server.controller.api.model.spec.ProcessConfig;
import org.kie.server.controller.api.model.spec.RuleConfig;
import org.kie.server.controller.api.model.spec.ServerConfig;
import org.kie.server.controller.api.model.spec.ServerTemplate;
import org.kie.server.controller.api.model.spec.ServerTemplateKey;
import org.kie.server.controller.api.model.spec.ServerTemplateList;
import org.kie.server.integrationtests.config.TestConfig;
import org.kie.server.integrationtests.controller.client.exception.UnexpectedResponseCodeException;
import org.kie.server.integrationtests.shared.filter.Authenticator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class KieServerMgmtControllerClient {
private static Logger logger = LoggerFactory.getLogger(KieServerMgmtControllerClient.class);
private static final String MANAGEMENT_LAST_URI_PART = "/management/servers";
private static final String CONTAINERS_LAST_URI_PART = "/containers";
private static final String MANAGEMENT_URI_PART = MANAGEMENT_LAST_URI_PART + "/";
private static final String CONTAINERS_URI_PART = CONTAINERS_LAST_URI_PART + "/";
private static final String STARTED_STATUS_URI_PART = "/status/started";
private static final String STOPPED_STATUS_URI_PART = "/status/stopped";
private static final String CONFIG_URI_PART = "/config/";
private String controllerBaseUrl;
private static final MarshallingFormat DEFAULT_MARSHALLING_FORMAT = MarshallingFormat.JAXB;
private MarshallingFormat format;
private Client httpClient;
protected Marshaller marshaller;
public KieServerMgmtControllerClient(String controllerBaseUrl, String login, String password) {
this(controllerBaseUrl, login, password, DEFAULT_MARSHALLING_FORMAT);
}
public KieServerMgmtControllerClient(String controllerBaseUrl, String login, String password, MarshallingFormat format) {
this.controllerBaseUrl = controllerBaseUrl;
httpClient = new ResteasyClientBuilder()
.establishConnectionTimeout(10, TimeUnit.SECONDS)
.socketTimeout(10, TimeUnit.SECONDS)
.build();
if (login == null) {
login = TestConfig.getUsername();
password = TestConfig.getPassword();
}
httpClient.register(new Authenticator(login, password));
setMarshallingFormat(format);
}
public ServerTemplate getServerTemplate(String serverTemplateId) {
return makeGetRequestAndCreateCustomResponse(controllerBaseUrl + MANAGEMENT_URI_PART + serverTemplateId, ServerTemplate.class);
}
public void saveContainerSpec(String serverTemplateId, ContainerSpec containerSpec ) {
makePutRequestAndCreateCustomResponse(controllerBaseUrl + MANAGEMENT_URI_PART + serverTemplateId + CONTAINERS_URI_PART + containerSpec.getId(), containerSpec, Object.class);
}
public void updateContainerSpec(String serverTemplateId, ContainerSpec containerSpec ) {
updateContainerSpec(serverTemplateId, containerSpec.getId(), containerSpec);
}
public void updateContainerSpec(String serverTemplateId, String containerId, ContainerSpec containerSpec) {
makePostRequestAndCreateCustomResponse(controllerBaseUrl + MANAGEMENT_URI_PART + serverTemplateId + CONTAINERS_URI_PART + containerId, containerSpec, Object.class);
}
public void saveServerTemplate(ServerTemplate serverTemplate) {
makePutRequestAndCreateCustomResponse(controllerBaseUrl + MANAGEMENT_URI_PART + serverTemplate.getId(), serverTemplate, Object.class);
}
public void deleteServerTemplate(String serverTemplateId) {
makeDeleteRequest(controllerBaseUrl + MANAGEMENT_URI_PART + serverTemplateId);
}
public ContainerSpec getContainerInfo(String serverTemplateId, String containerId) {
return makeGetRequestAndCreateCustomResponse(controllerBaseUrl + MANAGEMENT_URI_PART + serverTemplateId + CONTAINERS_URI_PART + containerId, ContainerSpec.class);
}
public void deleteContainerSpec(String serverTemplateId, String containerId) {
makeDeleteRequest(controllerBaseUrl + MANAGEMENT_URI_PART + serverTemplateId + CONTAINERS_URI_PART + containerId);
}
public Collection<ServerTemplate> listServerTemplates() {
ServerTemplateList serverTemplateList = makeGetRequestAndCreateCustomResponse(controllerBaseUrl + MANAGEMENT_LAST_URI_PART, ServerTemplateList.class);
if (serverTemplateList != null && serverTemplateList.getServerTemplates() != null) {
return Arrays.asList(serverTemplateList.getServerTemplates());
}
return Collections.emptyList();
}
public Collection<ContainerSpec> listContainerSpec(String serverTemplateId) {
ContainerSpecList containerSpecList = makeGetRequestAndCreateCustomResponse(controllerBaseUrl + MANAGEMENT_URI_PART + serverTemplateId + CONTAINERS_LAST_URI_PART, ContainerSpecList.class);
if (containerSpecList != null && containerSpecList.getContainerSpecs() != null) {
return Arrays.asList(containerSpecList.getContainerSpecs());
}
return Collections.emptyList();
}
public void startContainer(String serverTemplateId, String containerId) {
makePostRequestAndCreateCustomResponse(controllerBaseUrl + MANAGEMENT_URI_PART + serverTemplateId + CONTAINERS_URI_PART + containerId + STARTED_STATUS_URI_PART, "", null);
}
public void stopContainer(String serverTemplateId, String containerId) {
makePostRequestAndCreateCustomResponse(controllerBaseUrl + MANAGEMENT_URI_PART + serverTemplateId + CONTAINERS_URI_PART + containerId + STOPPED_STATUS_URI_PART, "", null);
}
public void updateContainerConfig(String serverTemplateId, String containerId, Capability capability, ContainerConfig config) {
makePostRequestAndCreateCustomResponse(controllerBaseUrl + MANAGEMENT_URI_PART + serverTemplateId + CONTAINERS_URI_PART + containerId + CONFIG_URI_PART + capability.toString(), config, Object.class);
}
private <T> T makeGetRequestAndCreateCustomResponse(String uri, Class<T> resultType) {
WebTarget clientRequest = httpClient.target(uri);
Response response;
response = clientRequest.request(getMediaType(format)).get();
if ( response.getStatus() == Response.Status.OK.getStatusCode() ) {
return deserialize(response, resultType);
} else {
throw createExceptionForUnexpectedResponseCode( clientRequest, response );
}
}
private void makeDeleteRequest(String uri) {
WebTarget clientRequest = httpClient.target(uri);
Response response;
try {
response = clientRequest.request(getMediaType(format)).delete();
response.close();
} catch (Exception e) {
throw createExceptionForUnexpectedFailure(clientRequest, e);
}
if ( response.getStatus() != Response.Status.NO_CONTENT.getStatusCode() ) {
throw createExceptionForUnexpectedResponseCode( clientRequest, response );
}
}
private <T> T makePutRequestAndCreateCustomResponse(String uri, Object bodyObject, Class<T> resultType) {
WebTarget clientRequest = httpClient.target(uri);
Response response;
try {
Entity<String> requestEntity = Entity.entity(serialize(bodyObject), getMediaType(format));
response = clientRequest.request(getMediaType(format)).put(requestEntity);
} catch (Exception e) {
throw createExceptionForUnexpectedFailure(clientRequest, e);
}
if ( response.getStatus() == Response.Status.CREATED.getStatusCode() ) {
return deserialize(response, resultType);
} else {
throw createExceptionForUnexpectedResponseCode( clientRequest, response );
}
}
private <T> T makePostRequestAndCreateCustomResponse(String uri, Object bodyObject, Class<T> resultType) {
WebTarget clientRequest = httpClient.target(uri);
Response response;
try {
Entity<String> requestEntity = Entity.entity(serialize(bodyObject), getMediaType(format));
response = clientRequest.request(getMediaType(format)).post(requestEntity);
} catch (Exception e) {
throw createExceptionForUnexpectedFailure(clientRequest, e);
}
if ( response.getStatus() == Response.Status.CREATED.getStatusCode() ||
response.getStatus() == Response.Status.OK.getStatusCode() ) {
return deserialize(response, resultType);
} else {
throw createExceptionForUnexpectedResponseCode( clientRequest, response );
}
}
private RuntimeException createExceptionForUnexpectedResponseCode(
WebTarget request,
Response response) {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("Unexpected HTTP response code when requesting URI '");
stringBuffer.append(getClientRequestUri(request));
stringBuffer.append("'! Response code: ");
stringBuffer.append(response.getStatus());
try {
String responseEntity = response.readEntity(String.class);
stringBuffer.append(" Response message: ");
stringBuffer.append(responseEntity);
} catch (IllegalStateException e) {
response.close();
// Exception while reading response - most probably empty response and closed input stream
}
logger.debug( stringBuffer.toString());
return new UnexpectedResponseCodeException(response.getStatus(), stringBuffer.toString());
}
private RuntimeException createExceptionForUnexpectedFailure(
WebTarget request, Exception e) {
String summaryMessage = "Unexpected exception when requesting URI '" + getClientRequestUri(request) + "'!";
logger.debug( summaryMessage);
return new RuntimeException(summaryMessage, e);
}
private String getClientRequestUri(WebTarget clientRequest) {
String uri;
try {
uri = clientRequest.getUri().toString();
} catch (Exception e) {
throw new RuntimeException("Malformed client URL was specified!", e);
}
return uri;
}
public void close() {
try {
httpClient.close();
} catch (Exception e) {
logger.error("Exception thrown while closing resources!", e);
}
}
public MarshallingFormat getMarshallingFormat() {
return format;
}
public void setMarshallingFormat(MarshallingFormat format) {
this.format = format;
Set<Class<?>> controllerClasses = new HashSet<Class<?>>();
controllerClasses.add(KieServerInstance.class);
controllerClasses.add(KieServerInstanceList.class);
controllerClasses.add(KieServerInstanceInfo.class);
controllerClasses.add(KieServerSetup.class);
controllerClasses.add(KieServerStatus.class);
controllerClasses.add(ServerInstance.class);
controllerClasses.add(ServerInstanceKey.class);
controllerClasses.add(ServerTemplate.class);
controllerClasses.add(ServerTemplateKey.class);
controllerClasses.add(ServerConfig.class);
controllerClasses.add(RuleConfig.class);
controllerClasses.add(ProcessConfig.class);
controllerClasses.add(ContainerSpec.class);
controllerClasses.add(ContainerSpecKey.class);
controllerClasses.add(Container.class);
controllerClasses.add(ContainerKey.class);
controllerClasses.add(ServerTemplateList.class);
controllerClasses.add(ContainerSpecList.class);
Set<Class<?>> minimalControllerClasses = new HashSet<Class<?>>();
minimalControllerClasses.add(RuleConfig.class);
minimalControllerClasses.add(ProcessConfig.class);
switch ( format ) {
case JAXB:
this.marshaller = MarshallerFactory.getMarshaller(controllerClasses, format, KieServerMgmtControllerClient.class.getClassLoader());
break;
case JSON:
this.marshaller = MarshallerFactory.getMarshaller(minimalControllerClasses, format, KieServerMgmtControllerClient.class.getClassLoader());
break;
default:
this.marshaller = MarshallerFactory.getMarshaller(controllerClasses, format, KieServerMgmtControllerClient.class.getClassLoader());
}
}
private String getMediaType( MarshallingFormat format ) {
switch ( format ) {
case JAXB: return MediaType.APPLICATION_XML;
case JSON: return MediaType.APPLICATION_JSON;
default: return MediaType.APPLICATION_XML;
}
}
protected String serialize(Object object) {
if (object == null) {
return "";
}
try {
return marshaller.marshall( object );
} catch ( MarshallingException e ) {
throw new RuntimeException( "Error while serializing request data!", e );
}
}
protected <T> T deserialize(Response response, Class<T> type) {
try {
if(type == null) {
return null;
}
String content = response.readEntity(String.class);
logger.debug("About to deserialize content: \n '{}' \n into type: '{}'", content, type);
if (content == null || content.isEmpty()) {
return null;
}
return marshaller.unmarshall( content, type );
} catch ( MarshallingException e ) {
throw new RuntimeException( "Error while deserializing data received from server!", e );
} finally {
response.close();
}
}
@SuppressWarnings("unchecked")
public static <T> Class<T> castClass(Class<?> aClass) {
return (Class<T>)aClass;
}
}