package io.cattle.platform.process.common.generic;
import io.cattle.platform.engine.manager.impl.ProcessRecord;
import io.cattle.platform.engine.process.ExitReason;
import io.cattle.platform.engine.process.LaunchConfiguration;
import io.cattle.platform.engine.process.impl.AbstractStatesBasedProcessState;
import io.cattle.platform.engine.process.impl.ProcessExecutionExitException;
import io.cattle.platform.engine.process.impl.ResourceStatesDefinition;
import io.cattle.platform.json.JsonMapper;
import io.cattle.platform.lock.definition.LockDefinition;
import io.cattle.platform.object.ObjectManager;
import io.cattle.platform.object.meta.ObjectMetaDataManager;
import io.cattle.platform.object.util.DataAccessor;
import io.cattle.platform.process.common.lock.ResourceChangeLock;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.jooq.exception.DataChangedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GenericResourceProcessState extends AbstractStatesBasedProcessState {
private static final Logger log = LoggerFactory.getLogger(GenericResourceProcessState.class);
Object resource;
String resourceId;
ObjectManager objectManager;
LockDefinition processLock;
Map<String, Object> data;
String state;
public GenericResourceProcessState(JsonMapper jsonMapper, ResourceStatesDefinition stateDef, LaunchConfiguration config, ObjectManager objectManager) {
super(jsonMapper, stateDef);
this.objectManager = objectManager;
this.resource = objectManager.loadResource(config.getResourceType(), config.getResourceId());
this.processLock = new ResourceChangeLock(config.getResourceType(), config.getResourceId());
this.resourceId = config.getResourceId();
this.data = config.getData();
this.state = lookupState();
}
@Override
public Object getResource() {
return resource;
}
@Override
public LockDefinition getProcessLock() {
return processLock;
}
protected String lookupState() {
try {
if (resource == null) {
return null;
}
return BeanUtils.getProperty(resource, getStatesDefinition().getStateField());
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
throw new IllegalStateException(e);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
@Override
public String getState() {
return state;
}
@Override
public void reload() {
resource = objectManager.reload(resource);
}
@Override
public void rebuild() {
resource = objectManager.reload(resource);
state = lookupState();
}
@Override
protected boolean setState(boolean transitioning, String oldState, String newState) {
reload();
if (resource != null && transitioning && ObjectMetaDataManager.STATE_FIELD.equals(getStatesDefinition().getStateField())) {
DataAccessor field = DataAccessor.fields(resource).withKey(ObjectMetaDataManager.TRANSITIONING_FIELD);
DataAccessor message = DataAccessor.fields(resource).withKey(ObjectMetaDataManager.TRANSITIONING_MESSAGE_FIELD);
for (DataAccessor accessor : new DataAccessor[] {field, message}) {
if (StringUtils.isNotBlank(accessor.as(String.class))) {
accessor.remove();
}
}
}
String resourceState = lookupState();
if (oldState == null || (!oldState.equals(resourceState) && !newState.equals(resourceState))) {
return false;
}
try {
Object newResource = objectManager.setFields(resource, getStatesDefinition().getStateField(), newState);
if (newResource == null) {
return false;
} else {
resource = newResource;
this.state = lookupState();
return true;
}
} catch (DataChangedException e) {
return false;
}
}
@Override
public void applyData(Map<String, Object> data) {
try {
resource = objectManager.setFields(resource, data);
} catch (DataChangedException e) {
throw new ProcessExecutionExitException(ExitReason.STATE_CHANGED);
}
}
@Override
protected Map<String, Object> convertMap(Map<Object, Object> data) {
return objectManager.convertToPropertiesFor(resource, data);
}
@Override
public String getResourceId() {
return resourceId;
}
@Override
public boolean shouldCancel(ProcessRecord record) {
if (resource == null) {
log.error("Resource is null, can't find resource id [{}]", resourceId);
return true;
}
return super.shouldCancel(record);
}
@Override
public Map<String, Object> getData() {
return data;
}
}