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    }