001package eu.cqse.check.framework.core;
002
003import org.conqat.lib.commons.assertion.CCSMAssert;
004import org.conqat.lib.commons.reflect.ReflectionUtils;
005
006import eu.cqse.check.framework.core.option.CheckOptionWrapper;
007
008/**
009 * A instance of a custom check. Multiple {@link CheckInstance}s of one
010 * {@link CheckImplementationBase} subtype can exist in order to be executed in
011 * parallel by multiple worker threads (each {@link CheckInstance} is backed by
012 * a separate instance of the {@link CheckImplementationBase} subtype).
013 */
014public class CheckInstance {
015
016        /** The check's implementation. */
017        private final CheckImplementationBase checkImplementation;
018
019        /** The check info. */
020        private final CheckInfo checkInfo;
021
022        /**
023         * Creates a new check instance with the given check info. This given check info
024         * must not be null.
025         */
026        public CheckInstance(CheckInfo checkInfo) throws CheckException {
027                CCSMAssert.isNotNull(checkInfo);
028                this.checkInfo = checkInfo;
029                checkImplementation = checkInfo.instantiateCheckImplementation();
030        }
031
032        /** Initializes the check. */
033        public void initialize() throws CheckException {
034                checkImplementation.initialize();
035        }
036
037        /** Executes this check with the given context. */
038        public void execute() throws CheckException {
039                checkImplementation.execute();
040        }
041
042        /** @see #checkImplementation */
043        public CheckImplementationBase getCheckImplementation() {
044                return checkImplementation;
045        }
046
047        /** @see #checkInfo */
048        public CheckInfo getCheckInfo() {
049                return checkInfo;
050        }
051
052        /**
053         * Initializes the underlying check implementation (calls
054         * {@link CheckImplementationBase#initialize()}) and then sets the check context
055         * of the underlying check implementation to the given one.
056         */
057        public void initializeAndSetContext(ICheckContext context) throws CheckException {
058                CCSMAssert.isNotNull(context);
059                checkImplementation.setContext(null); // ensure that initialize does not use old context info
060                initialize();
061                /*
062                 * initialize(); must be called while no context is set. This ensures that
063                 * implementations of the CheckImplementationBase#initialize method can't access
064                 * check-phase results (e.g., via context#accessPhaseResult). Initialization is
065                 * done only once for a batch of analyzed files but we store dependencies on
066                 * check-phase results on single-file granularity. Therefore, accessing
067                 * check-phase results from initialize() would mess up the information stored in
068                 * CheckPhaseResultDependencyIndex.
069                 */
070                checkImplementation.setContext(context);
071        }
072
073        /** Sets the option with the given name to the given value. */
074        public <T> void setOption(String name, T value) {
075                CheckOptionWrapper<?> option = checkInfo.getOptions().get(name);
076                if (option != null) {
077                        CCSMAssert.isTrue(ReflectionUtils.isAssignable(value.getClass(), option.getType()),
078                                        "The given value must have the same type as the option to set.");
079                        @SuppressWarnings("unchecked")
080                        CheckOptionWrapper<T> castedOption = (CheckOptionWrapper<T>) option;
081                        castedOption.setOption(checkImplementation, value);
082                }
083        }
084}