package org.ovirt.engine.api.restapi.resource;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import org.ovirt.engine.api.common.util.MutabilityAssertor;
import org.ovirt.engine.api.model.BaseResource;
import org.ovirt.engine.api.restapi.logging.Messages;
import org.ovirt.engine.core.common.action.VdcActionParametersBase;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.queries.VdcQueryParametersBase;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.compat.Guid;
public abstract class AbstractBackendSubResource<R extends BaseResource, Q /* extends IVdcQueryable */> extends
AbstractBackendResource<R, Q> {
private static final String[] STRICTLY_IMMUTABLE = { "id" };
protected String id;
protected Guid guid;
protected AbstractBackendSubResource(String id, Class<R> modelType, Class<Q> entityType) {
super(modelType, entityType);
this.id = id;
this.guid = asGuidOr404(id);
}
protected R performGet(VdcQueryType query, VdcQueryParametersBase params) {
return performGet(query, params, null);
}
protected R performGet(VdcQueryType query, VdcQueryParametersBase params, Class<? extends BaseResource> suggestedParentType) {
Q entity = getEntity(entityType, query, params, id, true);
return addLinks(populate(map(entity, null), entity), suggestedParentType);
}
protected <T> Q getEntity(EntityIdResolver<T> entityResolver, boolean notFoundAs404) {
try {
return entityResolver.resolve((T) guid);
} catch (Exception e) {
return handleError(entityType, e, notFoundAs404);
}
}
protected final <T> R performUpdate(R incoming,
Q entity,
R model,
EntityIdResolver<T> entityResolver,
VdcActionType update,
ParametersProvider<R, Q> updateProvider) {
entity = doUpdate(incoming, entity, model, entityResolver, update, updateProvider);
R model2 = map(entity);
deprecatedPopulate(model2, entity);
return addLinks(doPopulate(model2, entity));
}
protected <T> Q doUpdate(R incoming,
Q entity,
R model,
EntityIdResolver<T> entityResolver,
VdcActionType update,
ParametersProvider<R, Q> updateProvider) {
validateUpdate(incoming, model);
performAction(update, updateProvider.getParameters(incoming, entity));
entity = getEntity(entityResolver, false);
return entity;
}
protected <T> R performUpdate(R incoming,
EntityIdResolver<T> entityResolver,
VdcActionType update,
ParametersProvider<R, Q> updateProvider) {
Q entity = getEntity(entityResolver, true);
validateUpdate(incoming, map(entity));
// REVISIT maintain isolation across retrievals and update
entity = doUpdate(incoming, entity, entityResolver, update, updateProvider);
R model = map(entity);
deprecatedPopulate(model, entity);
return addLinks(doPopulate(model, entity));
}
protected <T> Q doUpdate(R incoming,
Q entity,
EntityIdResolver<T> entityResolver,
VdcActionType update,
ParametersProvider<R, Q> updateProvider) {
performAction(update, updateProvider.getParameters(incoming, entity));
entity = getEntity(entityResolver, false);
return entity;
}
/**
* Validate update from an immutability point of view.
*
* @param incoming
* the incoming resource representation
* @param existing
* the existing resource representation
* @throws WebApplicationException
* wrapping an appropriate response iff an immutability
* constraint has been broken
*/
protected void validateUpdate(R incoming, R existing) {
String reason = localize(Messages.BROKEN_CONSTRAINT_REASON);
String detail = localize(Messages.BROKEN_CONSTRAINT_DETAIL_TEMPLATE);
Response error = MutabilityAssertor.imposeConstraints(getStrictlyImmutable(), incoming, existing, reason, detail);
if (error != null) {
throw new WebApplicationException(error);
}
}
/**
* Override this method if any additional resource-specific fields are
* strictly immutable
*
* @return array of strict immutable field names
*/
protected String[] getStrictlyImmutable() {
return STRICTLY_IMMUTABLE;
}
protected interface ParametersProvider<R, Q> {
VdcActionParametersBase getParameters(R model, Q entity);
}
}