001 package org.apache.commons.contract;
002
003 import java.util.Map;
004
005 import org.apache.commons.contract.constraints.Constraints;
006 import org.apache.commons.contract.constraints.ValidationException;
007 import org.apache.commons.contract.descriptor.ParameterDescriptor;
008 import org.apache.commons.contract.descriptor.RequiredEnvironmentDescriptor;
009 import org.apache.commons.contract.descriptor.ResultDescriptor;
010 import org.apache.commons.contract.descriptor.ResultEntryDescriptor;
011 import org.apache.commons.i18n.XMLMessageProvider;
012 import org.apache.commons.i18n.bundles.ErrorBundle;
013
014 public class Executor {
015 static {
016 // FIXME - install() method has been removed
017 //XMLMessageProvider.install("contract/exceptions", Thread.currentThread().getContextClassLoader().getResourceAsStream("exceptions.xml"));
018 //XMLMessageProvider.install("contract/constraints", Thread.currentThread().getContextClassLoader().getResourceAsStream("constraints.xml"));
019 }
020
021 public static void init() {};
022
023 public static Result process(Processor processor, Map parameters, Context context) throws Exception {
024 prepareValues(processor.getParameterDescriptors(), parameters, context);
025 if ( processor instanceof EnvironmentConsumer ) {
026 checkRequirements((EnvironmentConsumer)processor, context);
027 }
028 Result result = processor.process(parameters, context);
029 validateResult(processor.getResultDescriptors(), result, context);
030 return result;
031 }
032
033 public static void prepareValues(ParameterDescriptor[] parameterDescriptors, Map parameters, Context context) throws ContractViolationException {
034 for ( int i = 0; i < parameterDescriptors.length; i++ ) {
035 String parameterName = parameterDescriptors[i].getName();
036 Object parameterValue = parameters.get(parameterName);
037 Object preparedValue = prepareValue(parameterDescriptors[i], parameterValue, context);
038 parameters.put(parameterName, preparedValue);
039 }
040 }
041
042 public static Object prepareValue(ParameterDescriptor parameterDescriptor, Object value, Context context) throws ContractViolationException {
043 Object preparedValue;
044 if ( value == null ) {
045 if ( parameterDescriptor.isRequired() ) {
046 throw new ContractViolationException(new ErrorBundle("requiredParameterMissing", new String[] { parameterDescriptor.getName() }));
047 } else {
048 preparedValue = parameterDescriptor.getDefaultValue();
049 }
050 } else {
051 try {
052 preparedValue = parameterDescriptor.getConstraints().cast(value, context);
053 parameterDescriptor.getConstraints().validate(preparedValue, context);
054 } catch ( ContractViolationException exception ) {
055 throw new ContractViolationException(new ErrorBundle("invalidParameter", new Object[] { parameterDescriptor.getName() }), exception);
056 }
057 }
058 return preparedValue;
059 }
060
061 public static void checkRequirements(EnvironmentConsumer processor, Context context) throws ContractViolationException {
062 RequiredEnvironmentDescriptor[] requirementDescriptor = processor.getRequiredEnvironmentDescriptors();
063 for ( int i = 0; i < requirementDescriptor.length; i++ ) {
064 Store store = context.getStore(requirementDescriptor[i].getStore());
065 try {
066 Object value = store.get(requirementDescriptor[i].getName(), context);
067 if ( value == null ) {
068 if ( requirementDescriptor[i].isRequired() ) {
069 throw new ValidationException(new ErrorBundle("requiredContextMissing", new Object[] { requirementDescriptor[i].getName(), requirementDescriptor[i].getStore()}));
070 } else {
071 value = requirementDescriptor[i].getDefaultValue();
072 store.put(requirementDescriptor[i].getName(), value, context);
073 }
074 }
075 Object castedValue = requirementDescriptor[i].getConstraints().cast(value, context);
076 requirementDescriptor[i].getConstraints().validate(castedValue, context);
077 if ( castedValue != value ) {
078 store.put(requirementDescriptor[i].getName(), castedValue, context);
079 }
080 } catch ( StoreException exception ) {
081 throw new ContractViolationException(new ErrorBundle("storeUnaccessable", new Object[] { requirementDescriptor[i].getName(), requirementDescriptor[i].getStore()}));
082 }
083 }
084 }
085
086
087 public static void validateResult(ResultDescriptor[] resultDescriptors, Result result, Context context) throws ContractViolationException {
088 ResultEntryDescriptor []entryDescriptors = getResultDescriptorByState(resultDescriptors, result.getState()).getResultEntryDescriptors();
089 Map resultEntries = result.getResultEntries();
090 String name = null;
091 Object value = null;
092 try {
093 for ( int i = 0; i < entryDescriptors.length; i++ ) {
094 ResultEntryDescriptor entryDescriptor = entryDescriptors[i];
095 name = entryDescriptor.getName();
096 value = resultEntries.get(name);
097 if ( value == null ) throw new ContractViolationException(new ErrorBundle("missingResultEntry", new String[] { name }));
098 Constraints constraints = entryDescriptor.getConstraints();
099 if ( constraints == null ) throw new ContractViolationException(new ErrorBundle("undefinedResultEntryConstraints", new String[] { name }));
100 value = constraints.cast(value, context);
101 entryDescriptor.getConstraints().validate(value, context);
102 resultEntries.put(name, value);
103 }
104 } catch ( ValidationException exception ) {
105 throw new ContractViolationException(new ErrorBundle("invalidResultEntry", new Object[] { name, value }), exception);
106 }
107 }
108
109 public static ResultDescriptor getResultDescriptorByState(ResultDescriptor[] resultDescriptors, String state) throws ContractViolationException {
110 for ( int i = 0; i < resultDescriptors.length; i++ ) {
111 if ( resultDescriptors[i].getStateDescriptor().getState().equals(state)) {
112 return resultDescriptors[i];
113 }
114 }
115 throw new ContractViolationException(new ErrorBundle("stateNotDefined", new Object[] { state }));
116 }
117 }