package org.zstack.core.scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.SimpleQuery;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.apimediator.ApiMessageInterceptionException;
import org.zstack.header.apimediator.ApiMessageInterceptor;
import org.zstack.header.apimediator.StopRoutingException;
import org.zstack.header.core.scheduler.APICreateSchedulerMessage;
import org.zstack.header.core.scheduler.SchedulerState;
import org.zstack.header.core.scheduler.SchedulerVO;
import org.zstack.header.core.scheduler.SchedulerVO_;
import org.zstack.header.errorcode.SysErrors;
import org.zstack.header.message.APIMessage;
import static org.zstack.core.Platform.argerr;
import static org.zstack.core.Platform.operr;
/**
* Created by Mei Lei on 7/5/16.
*/
public class SchedulerApiInterceptor implements ApiMessageInterceptor {
@Autowired
private CloudBus bus;
@Autowired
private DatabaseFacade dbf;
@Autowired
private ErrorFacade errf;
private void setServiceId(APIMessage msg) {
if (msg instanceof SchedulerMessage) {
SchedulerMessage schedmsg = (SchedulerMessage) msg;
bus.makeTargetServiceIdByResourceUuid(msg, SchedulerConstant.SERVICE_ID, schedmsg.getSchedulerUuid());
}
}
@Override
public APIMessage intercept(APIMessage msg) throws ApiMessageInterceptionException {
setServiceId(msg);
if (msg instanceof APIDeleteSchedulerMsg) {
validate((APIDeleteSchedulerMsg) msg);
} else if (msg instanceof APIUpdateSchedulerMsg) {
validate((APIUpdateSchedulerMsg) msg);
} else if (msg instanceof APICreateSchedulerMessage ) {
validate((APICreateSchedulerMessage) msg);
} else if (msg instanceof APIChangeSchedulerStateMsg) {
validate((APIChangeSchedulerStateMsg) msg);
}
return msg;
}
private void validate(APIDeleteSchedulerMsg msg) {
if (!dbf.isExist(msg.getUuid(), SchedulerVO.class)) {
APIDeleteSchedulerEvent evt = new APIDeleteSchedulerEvent(msg.getId());
bus.publish(evt);
throw new StopRoutingException();
}
}
private void validate(APIUpdateSchedulerMsg msg) {
if (!dbf.isExist(msg.getUuid(), SchedulerVO.class)) {
APIUpdateSchedulerEvent evt = new APIUpdateSchedulerEvent(msg.getId());
bus.publish(evt);
throw new StopRoutingException();
}
}
private void validate(APIChangeSchedulerStateMsg msg) {
if (!dbf.isExist(msg.getUuid(), SchedulerVO.class)) {
APIUpdateSchedulerEvent evt = new APIUpdateSchedulerEvent(msg.getId());
bus.publish(evt);
throw new StopRoutingException();
}
SimpleQuery<SchedulerVO> q = dbf.createQuery(SchedulerVO.class);
q.select(SchedulerVO_.state);
q.add(SchedulerVO_.uuid, SimpleQuery.Op.EQ, msg.getUuid());
String state = q.findValue();
if (msg.getStateEvent().equals("enable") && state.equals(SchedulerState.Enabled.toString())) {
throw new ApiMessageInterceptionException(operr("can not enable a Enabled scheduler" ));
}
if (msg.getStateEvent().equals("disable") && state.equals(SchedulerState.Disabled.toString())) {
throw new ApiMessageInterceptionException(operr("can not disable a Disabled scheduler"));
}
}
private void validate(APICreateSchedulerMessage msg) {
if (msg.getType().equals("simple")) {
if (msg.getInterval() == null) {
if (msg.getRepeatCount() != null) {
if (msg.getRepeatCount() != 1) {
throw new ApiMessageInterceptionException(argerr("interval must be set when use simple scheduler when repeat more than once"));
}
} else {
throw new ApiMessageInterceptionException(argerr("interval must be set when use simple scheduler when repeat forever"));
}
} else if (msg.getInterval() != null) {
if (msg.getRepeatCount() != null) {
if (msg.getInterval() <= 0) {
throw new ApiMessageInterceptionException(argerr("interval must be positive integer"));
} else if ((long) msg.getInterval() * (long) msg.getRepeatCount() * 1000L + msg.getStartTime() < 0 ) {
throw new ApiMessageInterceptionException(argerr("duration time out of range"));
} else if ((long) msg.getInterval() * (long) msg.getRepeatCount() * 1000L + msg.getStartTime() > 2147454847000L) {
throw new ApiMessageInterceptionException(argerr("stopTime out of mysql timestamp range"));
}
}
}
if (msg.getStartTime() == null) {
throw new ApiMessageInterceptionException(argerr("startTime must be set when use simple scheduler"));
} else if (msg.getStartTime() != null && msg.getStartTime() < 0) {
throw new ApiMessageInterceptionException(argerr("startTime must be positive integer or 0"));
} else if (msg.getStartTime() != null && msg.getStartTime() > 2147454847 ){
// mysql timestamp range is '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC.
// we accept 0 as startDate means start from current time
throw new ApiMessageInterceptionException(argerr("startTime out of range"));
}
if (msg.getRepeatCount() != null && msg.getRepeatCount() <= 0) {
throw new ApiMessageInterceptionException(argerr("repeatCount must be positive integer"));
}
}
if (msg.getType().equals("cron")) {
if (msg.getCron() == null || ( msg.getCron() != null && msg.getCron().isEmpty())) {
throw new ApiMessageInterceptionException(argerr("cron must be set when use cron scheduler"));
}
if ( (! msg.getCron().contains("?")) || msg.getCron().split(" ").length != 6) {
throw new ApiMessageInterceptionException(argerr("cron task must follow format like this : \"0 0/3 17-23 * * ?\" "));
}
if (msg.getInterval() != null || msg.getRepeatCount() != null || msg.getStartTime() != null) {
throw new ApiMessageInterceptionException(argerr("cron scheduler only need to specify cron task"));
}
}
}
}