/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.activemq.artemis.tests.integration.rest.util;
import java.io.Closeable;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
public abstract class RestMessageContext implements Closeable {
public static final String KEY_MSG_CREATE = "msg-create";
public static final String KEY_MSG_CREATE_ID = "msg-create-with-id";
public static final String KEY_MSG_PULL = "msg-pull-consumers";
public static final String KEY_MSG_PUSH = "msg-push-consumers";
public static final String KEY_MSG_PULL_SUB = "msg-pull-subscriptions";
public static final String KEY_MSG_PUSH_SUB = "msg-push-subscriptions";
public static final String KEY_MSG_CREATE_NEXT = "msg-create-next";
public static final String KEY_PULL_CONSUMERS_LOC = "pull-consumers-location";
public static final String KEY_MSG_CONSUME_NEXT = "msg-consume-next";
public static final String KEY_MSG_CONSUMER = "msg-consumer";
public static final String KEY_MSG_ACK_NEXT = "msg-acknowledge-next";
public static final String KEY_MSG_ACK = "msg-acknowledgement";
protected RestAMQConnection connection;
protected String destination;
protected Map<String, String> contextMap = new HashMap<>();
// consumer options
protected boolean autoAck;
protected boolean pushConsumer;
public RestMessageContext(RestAMQConnection restAMQConnection, String dest) throws IOException {
this(restAMQConnection, dest, true, false);
}
public RestMessageContext(RestAMQConnection restAMQConnection,
String dest,
boolean isAutoAck,
boolean isPush) throws IOException {
this.connection = restAMQConnection;
this.destination = dest;
this.autoAck = isAutoAck;
this.pushConsumer = isPush;
prepareSelf();
}
private void prepareSelf() throws IOException {
String destLink = getDestLink();
CloseableHttpResponse response = connection.request(destLink);
int code = ResponseUtil.getHttpCode(response);
if (code != 200) {
System.out.println("failed to init " + destLink);
System.out.println("reason: " + ResponseUtil.getDetails(response));
}
try {
Header header = response.getFirstHeader(KEY_MSG_CREATE);
contextMap.put(KEY_MSG_CREATE, header.getValue());
header = response.getFirstHeader(KEY_MSG_CREATE_ID);
contextMap.put(KEY_MSG_CREATE_ID, header.getValue());
header = response.getFirstHeader(KEY_MSG_PULL);
if (header != null) {
contextMap.put(KEY_MSG_PULL, header.getValue());
}
header = response.getFirstHeader(KEY_MSG_PUSH);
if (header != null) {
contextMap.put(KEY_MSG_PUSH, header.getValue());
}
header = response.getFirstHeader(KEY_MSG_PULL_SUB);
if (header != null) {
contextMap.put(KEY_MSG_PULL_SUB, header.getValue());
}
header = response.getFirstHeader(KEY_MSG_PUSH_SUB);
if (header != null) {
contextMap.put(KEY_MSG_PUSH_SUB, header.getValue());
}
} finally {
response.close();
}
}
protected abstract String getDestLink();
protected abstract String getPullConsumerUri();
protected abstract String getPushLink(String pushTarget);
public int postMessage(String content, String type) throws IOException {
String postUri;
String nextMsgUri = contextMap.get(KEY_MSG_CREATE_NEXT);
if (nextMsgUri == null) {
postUri = contextMap.get(KEY_MSG_CREATE);
} else {
postUri = nextMsgUri;
}
CloseableHttpResponse response = connection.post(postUri, type, content);
int code = -1;
try {
code = ResponseUtil.getHttpCode(response);
// check redirection
if (code == 307) {
Header redirLoc = response.getFirstHeader("Location");
contextMap.put(KEY_MSG_CREATE_NEXT, redirLoc.getValue());
code = postMessage(content, type);// do it again.
} else if (code == 201) {
Header header = response.getFirstHeader(KEY_MSG_CREATE_NEXT);
contextMap.put(KEY_MSG_CREATE_NEXT, header.getValue());
}
} finally {
response.close();
}
return code;
}
public abstract void initPullConsumers() throws IOException;
public boolean acknowledgement(boolean ackValue) throws IOException {
String ackUri = contextMap.get(KEY_MSG_ACK);
if (ackUri != null) {
CloseableHttpResponse response = connection.post(ackUri, "application/x-www-form-urlencoded", "acknowledge=" + ackValue);
int code = ResponseUtil.getHttpCode(response);
if (code == 200) {
contextMap.put(KEY_MSG_ACK_NEXT, response.getFirstHeader(KEY_MSG_ACK_NEXT).getValue());
}
return true;
}
return false;
}
public String pullMessage() throws IOException {
String message = null;
String msgPullUri = null;
if (autoAck) {
msgPullUri = contextMap.get(KEY_MSG_CONSUME_NEXT);
if (msgPullUri == null) {
initPullConsumers();
msgPullUri = contextMap.get(KEY_MSG_CONSUME_NEXT);
}
} else {
msgPullUri = contextMap.get(KEY_MSG_ACK_NEXT);
if (msgPullUri == null) {
initPullConsumers();
msgPullUri = contextMap.get(KEY_MSG_ACK_NEXT);
}
}
CloseableHttpResponse response = connection.post(msgPullUri);
int code = ResponseUtil.getHttpCode(response);
try {
if (code == 200) {
// success
HttpEntity entity = response.getEntity();
long len = entity.getContentLength();
if (len != -1 && len < 1024000) {
message = EntityUtils.toString(entity);
} else {
// drop message
System.err.println("Message too large, drop it " + len);
}
Header header = response.getFirstHeader(KEY_MSG_CONSUMER);
contextMap.put(KEY_MSG_CONSUMER, header.getValue());
if (!autoAck) {
header = response.getFirstHeader(KEY_MSG_ACK);
contextMap.put(KEY_MSG_ACK, header.getValue());
} else {
header = response.getFirstHeader(KEY_MSG_CONSUME_NEXT);
contextMap.put(KEY_MSG_CONSUME_NEXT, header.getValue());
}
} else if (code == 503) {
if (autoAck) {
contextMap.put(KEY_MSG_CONSUME_NEXT, response.getFirstHeader(KEY_MSG_CONSUME_NEXT).getValue());
} else {
contextMap.put(KEY_MSG_ACK_NEXT, response.getFirstHeader(KEY_MSG_ACK_NEXT).getValue());
}
Header header = response.getFirstHeader("Retry-After");
if (header != null) {
long retryDelay = Long.valueOf(response.getFirstHeader("Retry-After").getValue());
try {
Thread.sleep(retryDelay);
} catch (InterruptedException e) {
e.printStackTrace();
}
message = pullMessage();
}
} else {
throw new IllegalStateException("error: " + ResponseUtil.getDetails(response));
}
} finally {
response.close();
}
return message;
}
@Override
public void close() {
String consumerUri = contextMap.get(KEY_MSG_CONSUMER);
if (consumerUri != null) {
try {
connection.delete(consumerUri);
contextMap.remove(KEY_MSG_CONSUMER);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void setUpPush(String pushTarget) throws Exception {
String pushLink = this.contextMap.get(KEY_MSG_PUSH);
String pushRegXml = "<push-registration>" +
"<link rel=\"destination\" href=\"" +
this.connection.getTargetUri() +
this.getPushLink(pushTarget) + "\"/>" +
"</push-registration>";
CloseableHttpResponse response = connection.post(pushLink, "application/xml", pushRegXml);
int code = ResponseUtil.getHttpCode(response);
try {
if (code != 201) {
System.out.println("Failed to push " + pushRegXml);
System.out.println("Location: " + pushLink);
throw new Exception("Failed to register push " + ResponseUtil.getDetails(response));
}
} finally {
response.close();
}
}
}