/*
* Copyright (c) 2010 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ovirt.engine.api.common.util;
import static org.ovirt.engine.api.utils.ReflectionHelper.capitalize;
import static org.ovirt.engine.api.utils.ReflectionHelper.different;
import static org.ovirt.engine.api.utils.ReflectionHelper.isSet;
import java.text.MessageFormat;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import org.ovirt.engine.api.model.BaseResource;
import org.ovirt.engine.api.model.Fault;
/**
* Used to assert that fields set on a model type do not conflict with
* mutability constraints
*/
public class MutabilityAssertor {
// REVISIT: i18n
private static final String BROKEN_CONSTRAINT_REASON = "Broken immutability constraint";
private static final String BROKEN_CONSTRAINT_DETAIL = "Attempt to set immutable field: {0}";
// REVISIT: is "409 Conflicted" actually the appropriate status here?
// The idea is to convey a conflict with the fundamental immutable state
// of the resource, but it also carries connotations of a dirty update
private static final Response.Status BROKEN_CONSTRAINT_STATUS = Response.Status.CONFLICT;
/**
* Validate update from an immutability point of view.
*
* @param <T> representation type
* @param strict array of strictly immutable field names
* @param incoming the incoming representation
* @param existing the existing representation
* @throws WebApplicationException wrapping an appropriate response
* iff an immutability constraint has been broken
*/
public static <T extends BaseResource> void validateUpdate(String[] strict, T incoming, T existing) {
Response error = imposeConstraints(strict, incoming, existing);
if (error != null) {
throw new WebApplicationException(error);
}
}
/**
* Impose immutability constraints.
*
* @param <T> representation type
* @param strict array of strictly immutable field names
* @param incoming incoming representation
* @param existing existing representation
* @return error Response if appropriate
*/
public static <T extends BaseResource> Response imposeConstraints(String[] strict, T incoming, T existing) {
return imposeConstraints(strict, incoming, existing, BROKEN_CONSTRAINT_REASON, BROKEN_CONSTRAINT_DETAIL);
}
/**
* Impose immutability constraints.
*
* @param <T> representation type
* @param strict array of strictly immutable field names
* @param incoming incoming representation
* @param existing existing representation
* @param reason the fault reason
* @param detail the fault detail
* @return error Response if appropriate
*/
public static <T extends BaseResource> Response imposeConstraints(String[] strict, T incoming, T existing, String reason, String detail) {
for (String s: strict) {
String field = capitalize(s);
if (isSet(incoming, field) && different(incoming, existing, field)) {
Fault fault = new Fault();
fault.setReason(reason);
fault.setDetail(MessageFormat.format(detail, s));
return Response.status(BROKEN_CONSTRAINT_STATUS)
.entity(fault)
.build();
}
}
return null;
}
}