package org.zstack.core;
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.errorcode.ErrorFacade;
import org.zstack.core.thread.SyncTaskChain;
import org.zstack.header.core.workflow.FlowTrigger;
import org.zstack.header.core.AsyncBackup;
import org.zstack.header.core.Completion;
import org.zstack.header.core.NoErrorCompletion;
import org.zstack.header.core.ReturnValueCompletion;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.message.Message;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
/**
*/
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class With {
private static final CLogger logger = Utils.getLogger(With.class);
private Message[] msgs;
private AsyncBackup backup;
@Autowired
private CloudBus bus;
@Autowired
private ErrorFacade errf;
public With(AsyncBackup backup, Message...msgs) {
this.backup = backup;
this.msgs = msgs;
check();
}
public With(AsyncBackup backup) {
this.backup = backup;
check();
}
public With(Message...msgs) {
this.msgs = msgs;
}
private void backup(Throwable t) {
if (!(backup instanceof Message)) {
logger.warn(String.format("unhandled exception happened"), t);
}
ErrorCode err = errf.throwableToInternalError(t);
if (backup instanceof Completion) {
((Completion)backup).fail(err);
} else if (backup instanceof ReturnValueCompletion) {
((ReturnValueCompletion)backup).fail(err);
} else if (backup instanceof FlowTrigger) {
((FlowTrigger) backup).fail(err);
} else if (backup instanceof SyncTaskChain) {
((SyncTaskChain) backup).next();
} else if (backup instanceof NoErrorCompletion) {
((NoErrorCompletion) backup).done();
} else if (backup instanceof Message) {
bus.logExceptionWithMessageDump((Message) backup, t);
bus.replyErrorByMessageType((Message) backup, err);
} else {
throw new CloudRuntimeException("should not be here");
}
if (msgs != null) {
for (Message msg : msgs) {
bus.logExceptionWithMessageDump(msg, t);
bus.replyErrorByMessageType(msg, err);
}
}
}
private void check() {
if (backup == null) {
return;
}
if (!(
backup instanceof Completion || backup instanceof ReturnValueCompletion || backup instanceof Message
|| backup instanceof FlowTrigger || backup instanceof SyncTaskChain || backup instanceof NoErrorCompletion
)) {
String info = String.format("%s is not a known AsyncBackup. Someone added this type but forgot changing AsyncBackupAspect, please file bug", backup.getClass().getName());
throw new CloudRuntimeException(info);
}
}
public void run(Runnable runnable) {
try {
runnable.run();
} catch (Throwable t) {
backup(t);
}
}
public void runWithException(Runnable runnable) {
try {
runnable.run();
} catch (RuntimeException re) {
backup(re);
throw re;
} catch (Error err) {
backup(err);
throw err;
}
}
}