package org.zstack.compute.zone;
import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.Platform;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.MessageSafe;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.DbEntityLister;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.AbstractService;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.errorcode.SysErrors;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.Message;
import org.zstack.header.zone.*;
import org.zstack.search.SearchQuery;
import org.zstack.tag.TagManager;
import org.zstack.utils.ObjectUtils;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
import java.util.*;
import static java.util.Arrays.asList;
public class ZoneManagerImpl extends AbstractService implements ZoneManager {
private final static CLogger logger = Utils.getLogger(ZoneManager.class);
@Autowired
private CloudBus bus;
@Autowired
private DatabaseFacade dbf;
@Autowired
private PluginRegistry pluginRgty;
@Autowired
private DbEntityLister dl;
@Autowired
private ErrorFacade errf;
@Autowired
private TagManager tagMgr;
private Map<String, ZoneFactory> zoneFactories = Collections.synchronizedMap(new HashMap<String, ZoneFactory>());
private static final Set<Class> allowedMessageAfterSoftDeletion = new HashSet<Class>();
static {
allowedMessageAfterSoftDeletion.add(ZoneDeletionMsg.class);
}
@Override
@MessageSafe
public void handleMessage(Message msg) {
if (msg instanceof APIMessage) {
handleApiMessage((APIMessage)msg);
} else {
handleLocalMessage(msg);
}
}
private void handleLocalMessage(Message msg) {
if (msg instanceof ZoneMessage) {
passThrough((ZoneMessage)msg);
} else {
bus.dealWithUnknownMessage(msg);
}
}
private void handleApiMessage(APIMessage msg) {
if (msg instanceof APICreateZoneMsg) {
handle((APICreateZoneMsg) msg);
} else if (msg instanceof ZoneMessage) {
passThrough((ZoneMessage)msg);
} else if (msg instanceof APIListZonesMsg) {
handle((APIListZonesMsg) msg);
} else if (msg instanceof APISearchZoneMsg) {
handle((APISearchZoneMsg) msg);
} else if (msg instanceof APIGetZoneMsg) {
handle((APIGetZoneMsg) msg);
} else {
bus.dealWithUnknownMessage(msg);
}
}
private void handle(APIGetZoneMsg msg) {
APIGetZoneReply reply = new APIGetZoneReply();
if (msg.getUuid() != null) {
ZoneVO vo = dbf.findByUuid(msg.getUuid(), ZoneVO.class);
reply.setInventories(asList(ZoneInventory.valueOf(vo)));
} else {
reply.setInventories(ZoneInventory.valueOf(dbf.listAll(ZoneVO.class)));
}
bus.reply(msg, reply);
}
private void handle(APISearchZoneMsg msg) {
SearchQuery<ZoneInventory> query = SearchQuery.create(msg, ZoneInventory.class);
String res = query.listAsString();
APISearchZoneReply reply = new APISearchZoneReply();
reply.setContent(res);
bus.reply(msg, reply);
}
private void passThrough(ZoneMessage msg) {
ZoneVO vo = dbf.findByUuid(msg.getZoneUuid(), ZoneVO.class);
if (vo == null && allowedMessageAfterSoftDeletion.contains(msg.getClass())) {
ZoneEO eo = dbf.findByUuid(msg.getZoneUuid(), ZoneEO.class);
vo = ObjectUtils.newAndCopy(eo, ZoneVO.class);
}
if (vo == null) {
ErrorCode err = errf.instantiateErrorCode(SysErrors.RESOURCE_NOT_FOUND, String.format("unable to find zone[uuid:%s], it may have been deleted", msg.getZoneUuid()));
bus.replyErrorByMessageType((Message)msg, err);
return;
}
ZoneFactory factory = this.getZoneFactory(ZoneType.valueOf(vo.getType()));
Zone zone = factory.getZone(vo);
zone.handleMessage((Message)msg);
}
private void handle(APIListZonesMsg msg) {
APIListZonesReply reply = new APIListZonesReply();
List<ZoneVO> vos = dl.listByApiMessage(msg, ZoneVO.class);
List<ZoneInventory> invs = ZoneInventory.valueOf(vos);
reply.setInventories(invs);
bus.reply(msg, reply);
}
private void handle(APICreateZoneMsg msg) {
String zoneType = msg.getType();
if (zoneType == null) {
zoneType = BaseZoneFactory.type.toString();
}
ZoneFactory factory = this.getZoneFactory(ZoneType.valueOf(zoneType));
APICreateZoneEvent evt = new APICreateZoneEvent(msg.getId());
ZoneVO vo = new ZoneVO();
if (msg.getResourceUuid() != null) {
vo.setUuid(msg.getResourceUuid());
} else {
vo.setUuid(Platform.getUuid());
}
vo.setName(msg.getName());
vo.setDescription(msg.getDescription());
vo = factory.createZone(vo, msg);
tagMgr.createTagsFromAPICreateMessage(msg, vo.getUuid(), ZoneVO.class.getSimpleName());
evt.setInventory(ZoneInventory.valueOf(vo));
logger.debug("Created zone: " + vo.getName() + " uuid:" + vo.getUuid());
bus.publish(evt);
}
@Override
public String getId() {
return bus.makeLocalServiceId(ZoneConstant.SERVICE_ID);
}
private void populateExtensions() {
for (ZoneFactory f : pluginRgty.getExtensionList(ZoneFactory.class)) {
ZoneFactory old = zoneFactories.get(f.getType().toString());
if (old != null) {
throw new CloudRuntimeException(String.format("duplicate ZoneFactory[%s, %s] for type[%s]",
f.getClass().getName(), old.getClass().getName(), f.getType()));
}
zoneFactories.put(f.getType().toString(), f);
}
}
@Override
public boolean start() {
populateExtensions();
return true;
}
@Override
public boolean stop() {
return true;
}
private ZoneFactory getZoneFactory(ZoneType type) {
ZoneFactory factory = zoneFactories.get(type.toString());
if (factory == null) {
throw new CloudRuntimeException(String.format("No ZoneFactory of type[%s] found", type));
}
return factory;
}
}