/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* 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 io.undertow.server.handlers.proxy.mod_cluster;
import java.io.Closeable;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import io.undertow.testutils.HttpClientUtils;
import io.undertow.util.StatusCodes;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.junit.Assert;
/**
* Basic mod_cluster management client. This can be used to simulate management requests to the mod_cluster manager.
*
* @author Emanuel Muckenhuber
*/
public class MCMPTestClient implements Closeable {
public static final String CONFIG = new String("CONFIG");
public static final String ENABLE_APP = new String("ENABLE-APP");
public static final String DISABLE_APP = new String("DISABLE-APP");
public static final String STOP_APP = new String("STOP-APP");
public static final String REMOVE_APP = new String("REMOVE-APP");
public static final String STATUS = new String("STATUS");
public static final String DUMP = new String("DUMP");
public static final String INFO = new String("INFO");
public static final String PING = new String("PING");
public static final String GET = new String("GET");
private static final String[] YES_NO = new String[] { "Yes", "No" };
private final HttpClient client;
private final String manager;
private final String command;
public MCMPTestClient(HttpClient client, String manager) {
this.client = client;
this.manager = manager;
this.command = manager + "/*";
}
public String info() throws IOException {
final Request request = new Request(manager, INFO);
final HttpResponse result = client.execute(request);
return assertResponse(result);
}
public String registerNode(final NodeTestConfig config) throws IOException {
final Request request = new Request(manager, CONFIG);
final List<NameValuePair> pairs = new ArrayList<NameValuePair>();
addIfNotNull(pairs, MCMPConstants.BALANCER_STRING, config.getBalancerName());
addIfNotNull(pairs, MCMPConstants.STICKYSESSIONFORCE_STRING, config.getStickySessionForce(), YES_NO);
addIfNotNull(pairs, MCMPConstants.STICKYSESSIONCOOKIE_STRING, config.getStickySessionCookie());
addIfNotNull(pairs, MCMPConstants.JVMROUTE_STRING, config.getJvmRoute());
addIfNotNull(pairs, MCMPConstants.DOMAIN_STRING, config.getDomain());
addIfNotNull(pairs, MCMPConstants.TYPE_STRING, config.getType());
addIfNotNull(pairs, MCMPConstants.HOST_STRING, config.getHostname());
addIfNotNull(pairs, MCMPConstants.PORT_STRING, config.getPort());
request.setEntity(createEntity(pairs));
final HttpResponse result = client.execute(request);
return assertResponse(result);
}
static void addIfNotNull(final List<NameValuePair> pairs, final String key, final Boolean value, String[] inconsistentNames) {
if (value != null) {
pairs.add(new BasicNameValuePair(key, value ? inconsistentNames[0] : inconsistentNames[1]));
}
}
static void addIfNotNull(final List<NameValuePair> pairs, final String key, final Integer value) {
if (value != null) {
pairs.add(new BasicNameValuePair(key, value.toString()));
}
}
static void addIfNotNull(final List<NameValuePair> pairs, final String key, final String value) {
if (value != null) {
pairs.add(new BasicNameValuePair(key, value));
}
}
public String updateLoad(final String jvmRoute, int load) throws IOException {
final Request request = new Request(manager, STATUS);
request.setEntity(createEntity(new BasicNameValuePair("JVMRoute", jvmRoute), new BasicNameValuePair("Load", "" + load)));
final HttpResponse result = client.execute(request);
return assertResponse(result);
}
public String removeNode(String jvmRoute) throws IOException {
final Request request = new Request(command, REMOVE_APP);
request.setEntity(createEntity(new BasicNameValuePair("JVMRoute", jvmRoute)));
final HttpResponse response = client.execute(request);
return assertResponse(response);
}
public String enableApp(String jvmRoute, App app) throws IOException {
return enableApp(jvmRoute, app.getContext(), app.getHosts());
}
public String enableApp(String jvmRoute, String webApp, String... hosts) throws IOException {
return executeAppCmd(ENABLE_APP, jvmRoute, webApp, hosts);
}
public String disableApp(String jvmRoute, App app) throws IOException {
return disableApp(jvmRoute, app.getContext(), app.getHosts());
}
public String disableApp(String jvmRoute, String webApp, String... hosts) throws IOException {
return executeAppCmd(DISABLE_APP, jvmRoute, webApp, hosts);
}
public String stopApp(String jvmRoute, App app) throws IOException {
return stopApp(jvmRoute, app.getContext(), app.getHosts());
}
public String stopApp(String jvmRoute, String webApp, String... hosts) throws IOException {
return executeAppCmd(STOP_APP, jvmRoute, webApp, hosts);
}
public String removeApp(String jvmRoute, App app) throws IOException {
return removeApp(jvmRoute, app.getContext(), app.getHosts());
}
public String removeApp(String jvmRoute, String webApp, String... hosts) throws IOException {
return executeAppCmd(REMOVE_APP, jvmRoute, webApp, hosts);
}
public String ping(final String scheme, final String hostname, final int port) throws IOException {
final Request request = new Request(manager, PING);
final List<NameValuePair> pairs = new ArrayList<>();
addIfNotNull(pairs, MCMPConstants.SCHEME_STRING, scheme);
addIfNotNull(pairs, MCMPConstants.HOST_STRING, hostname);
addIfNotNull(pairs, MCMPConstants.PORT_STRING, port);
request.setEntity(createEntity(pairs));
final HttpResponse response = client.execute(request);
return HttpClientUtils.readResponse(response);
}
String executeAppCmd(final String command, final String jvmRoute, String webApp, String... hosts) throws IOException {
final Request request = new Request(manager, command);
request.setEntity(createEntity(new BasicNameValuePair("JVMRoute", jvmRoute), new BasicNameValuePair("context", webApp), new BasicNameValuePair("Alias", asString(Arrays.asList(hosts)))));
final HttpResponse result = client.execute(request);
return assertResponse(result);
}
@Override
public void close() throws IOException {
client.getConnectionManager().shutdown();
}
static String assertResponse(final HttpResponse result) throws IOException {
final String response = HttpClientUtils.readResponse(result);
Assert.assertEquals(response, StatusCodes.OK, result.getStatusLine().getStatusCode());
return response;
}
static HttpEntity createEntity(final NameValuePair... pairs) throws UnsupportedEncodingException {
return createEntity(Arrays.asList(pairs));
}
static HttpEntity createEntity(final List<NameValuePair> pairs) throws UnsupportedEncodingException {
return new UrlEncodedFormEntity(pairs, StandardCharsets.US_ASCII);
}
static class Request extends HttpPost {
private final String name;
Request(String uri, String name) {
this(URI.create(uri), name);
}
Request(URI uri, String name) {
super(uri);
this.name = name;
}
@Override
public String getMethod() {
return name;
}
}
String asString(List<String> names) {
final StringBuilder builder = new StringBuilder();
final Iterator<String> i = names.iterator();
while (i.hasNext()) {
builder.append(i.next());
if (i.hasNext()) {
builder.append(",");
}
}
return builder.toString();
}
static class App {
private final String context;
private final String[] hosts;
App(String context, String... hosts) {
this.context = context;
this.hosts = hosts;
}
public String getContext() {
return context;
}
public String[] getHosts() {
return hosts;
}
}
}