package org.zstack.test;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusEventListener;
import org.zstack.core.debug.APIDebugSignalMsg;
import org.zstack.core.debug.DebugSignal;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.core.progressbar.InProgressEvent;
import org.zstack.header.apimediator.ApiMediatorConstant;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.message.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static java.util.Arrays.asList;
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class ApiSender {
private APIEvent result;
private volatile boolean isTimeout = true;
private int timeout = 15;
@Autowired
private CloudBus bus;
@Autowired
private ErrorFacade errf;
public <T extends MessageReply> T call(APIMessage msg, Class clazz) throws ApiSenderException {
msg.setServiceId(ApiMediatorConstant.SERVICE_ID);
MessageReply r = bus.call(msg);
if (!r.isSuccess()) {
throw new ApiSenderException(r.getError());
} else {
return r.castReply();
}
}
private <T extends APIEvent> T doSend(final APIMessage msg, Class<? extends APIEvent> clazz, boolean exceptionOnError) throws ApiSenderException {
APIEvent resultEvent;
try {
resultEvent = clazz.newInstance();
} catch (Exception e) {
throw new CloudRuntimeException("Unable to create instance of " + clazz.getCanonicalName(), e);
}
msg.setServiceId(ApiMediatorConstant.SERVICE_ID);
final CountDownLatch count = new CountDownLatch(1);
bus.subscribeEvent(new CloudBusEventListener() {
@Override
public boolean handleEvent(Event e) {
APIEvent ae = (APIEvent) e;
if (ae instanceof InProgressEvent) {
return false;
}
if (msg.getId().equals(ae.getApiId())) {
result = ae;
isTimeout = false;
count.countDown();
return true;
}
return false;
}
}, resultEvent);
bus.send(msg);
try {
count.await(timeout, TimeUnit.SECONDS);
if (isTimeout) {
Api api = new Api();
APIDebugSignalMsg dmsg = new APIDebugSignalMsg();
dmsg.setServiceId(ApiMediatorConstant.SERVICE_ID);
dmsg.setSignals(asList(DebugSignal.DumpTaskQueue.toString()));
dmsg.setSession(api.loginAsAdmin());
bus.send(dmsg);
TimeUnit.SECONDS.sleep(2);
String errStr = String.format("%s[uuid:%s] timeout after %s seconds", msg.getMessageName(), msg.getId(), timeout);
throw new ApiSenderException(errf.stringToTimeoutError(errStr));
}
} catch (InterruptedException e1) {
throw new CloudRuntimeException("", e1);
}
if (!result.isSuccess()) {
if (exceptionOnError) {
throw new ApiSenderException(result.getError());
} else {
return null;
}
} else {
return (T) result;
}
}
public <T extends APIEvent> T send(APIMessage msg, Class<? extends APIEvent> clazz) throws ApiSenderException {
return doSend(msg, clazz, true);
}
public <T extends APIEvent> T send(APIMessage msg, Class<? extends APIEvent> clazz, boolean exceptionOnError) throws ApiSenderException {
return doSend(msg, clazz, exceptionOnError);
}
public <T extends APIReply> T list(APIListMessage msg) throws ApiSenderException {
msg.setServiceId(ApiMediatorConstant.SERVICE_ID);
APIReply reply = (APIReply) bus.call(msg);
if (!reply.isSuccess()) {
throw new ApiSenderException(reply.getError());
} else {
return (T) reply;
}
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
}