package org.zstack.compute.zone; 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.cascade.CascadeConstant; import org.zstack.core.cascade.CascadeFacade; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.header.core.NopeCompletion; import org.zstack.header.core.workflow.*; import org.zstack.header.errorcode.SysErrors; import org.zstack.core.job.JobQueueFacade; import org.zstack.core.workflow.*; import org.zstack.header.core.Completion; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.message.APIDeleteMessage; import org.zstack.header.message.APIMessage; import org.zstack.header.message.Message; import org.zstack.header.zone.*; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; import java.util.Arrays; import java.util.List; import java.util.Map; @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = true) public class ZoneBase extends AbstractZone { protected final static CLogger logger = Utils.getLogger(ZoneBase.class); protected ZoneVO self; @Autowired protected DatabaseFacade dbf; @Autowired protected CloudBus bus; @Autowired protected ZoneExtensionPointEmitter extpEmitter; @Autowired protected JobQueueFacade jobf; @Autowired protected CascadeFacade casf; @Autowired protected ErrorFacade errf; ZoneBase(ZoneVO self) { this.self = self; } protected void handle(APIChangeZoneStateMsg msg) { APIChangeZoneStateEvent evt = new APIChangeZoneStateEvent(msg.getId()); ZoneStateEvent stateEvt = ZoneStateEvent.valueOf(msg.getStateEvent()); try { extpEmitter.preChange(self, stateEvt); } catch (ZoneException e) { evt.setError(errf.instantiateErrorCode(SysErrors.CHANGE_RESOURCE_STATE_ERROR, e.getMessage())); bus.publish(evt); return; } ZoneState formerState = self.getState(); extpEmitter.beforeChange(self, stateEvt); ZoneState next = AbstractZone.getNextState(self.getState(), stateEvt); self.setState(next); self = dbf.updateAndRefresh(self); extpEmitter.afterChange(self, stateEvt, formerState); evt.setInventory(ZoneInventory.valueOf(self)); logger.debug(String.format("Changed state of zone[uuid:%s] from %s to %s by event %s", self.getUuid(), formerState, self.getState(), stateEvt)); bus.publish(evt); } protected void handleApiMessage(APIMessage msg) { if (msg instanceof APIDeleteZoneMsg) { handle((APIDeleteZoneMsg)msg); } else if (msg instanceof APIChangeZoneStateMsg) { handle((APIChangeZoneStateMsg) msg); } else if (msg instanceof APIUpdateZoneMsg) { handle((APIUpdateZoneMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } private void handle(APIUpdateZoneMsg msg) { boolean update = false; if (msg.getName() != null) { self.setName(msg.getName()); update = true; } if (msg.getDescription() != null) { self.setDescription(msg.getDescription()); update = true; } if (update) { self = dbf.updateAndRefresh(self); } APIUpdateZoneEvent evt = new APIUpdateZoneEvent(msg.getId()); evt.setInventory(ZoneInventory.valueOf(self)); bus.publish(evt); } protected void handle(APIDeleteZoneMsg msg) { final APIDeleteZoneEvent evt = new APIDeleteZoneEvent(msg.getId()); final String issuer = ZoneVO.class.getSimpleName(); ZoneInventory zinv = ZoneInventory.valueOf(self); final List<ZoneInventory> ctx = Arrays.asList(zinv); FlowChain chain = FlowChainBuilder.newSimpleFlowChain(); chain.setName(String.format("delete-zone-%s", msg.getUuid())); if (msg.getDeletionMode() == APIDeleteMessage.DeletionMode.Permissive) { chain.then(new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade(CascadeConstant.DELETION_CHECK_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }).then(new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade(CascadeConstant.DELETION_DELETE_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); } else { chain.then(new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade(CascadeConstant.DELETION_FORCE_DELETE_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); } chain.done(new FlowDoneHandler(msg) { @Override public void handle(Map data) { casf.asyncCascadeFull(CascadeConstant.DELETION_CLEANUP_CODE, issuer, ctx, new NopeCompletion()); bus.publish(evt); } }).error(new FlowErrorHandler(msg) { @Override public void handle(ErrorCode errCode, Map data) { evt.setError(errf.instantiateErrorCode(SysErrors.DELETE_RESOURCE_ERROR, errCode)); bus.publish(evt); } }).start(); } @Override public void handleMessage(Message msg) { try { if (msg instanceof APIMessage) { handleApiMessage((APIMessage)msg); } else { handleLocalMessage(msg); } } catch (Exception e) { bus.logExceptionWithMessageDump(msg, e); bus.replyErrorByMessageType(msg, e); } } protected void handleLocalMessage(Message msg) { if (msg instanceof ZoneDeletionMsg) { handle((ZoneDeletionMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } private void handle(ZoneDeletionMsg msg) { ZoneInventory inv = ZoneInventory.valueOf(self); extpEmitter.beforeDelete(inv); deleteHook(); extpEmitter.afterDelete(inv); ZoneDeletionReply reply = new ZoneDeletionReply(); bus.reply(msg, reply); } @Override protected void deleteHook() { } }