@Named("mvc")
@RequestScoped
public class MvcContextImpl implements MvcContext {

    private static final Logger log = Logger.getLogger(MvcContextImpl.class.getName());

    @Inject
    private Csrf csrf;

    @Inject
    private Encoders encoders;

    @Inject
    private ServletContext servletContext;

    @Inject
    private ApplicationUris applicationUris;

    @Inject
    @JaxRsContext
    private Configuration configuration;

    @Inject
    @JaxRsContext
    private UriInfo uriInfo;

    private Locale locale;

    private String applicationPath;

    @PostConstruct
    public void init() {

        Objects.requireNonNull(configuration, "Cannot obtain JAX-RS Configuration instance");
        Objects.requireNonNull(uriInfo, "Cannot obtain JAX-RS UriInfo instance");
        Objects.requireNonNull(servletContext, "Cannot obtain ServletContext");

        applicationPath = PathUtils.normalizePath(
                uriInfo.getBaseUri().getPath().substring(servletContext.getContextPath().length())
        );

    }

    @Override
    public String getBasePath() {
        if (applicationPath != null) {
            return servletContext.getContextPath() + applicationPath;
        }
        return servletContext.getContextPath();
    }

    @Override
    public Csrf getCsrf() {
        return csrf;
    }

    @Override
    public Encoders getEncoders() {
        return encoders;
    }

    @Override
    public Configuration getConfig() {
        return configuration;
    }

    @Override
    public Locale getLocale() {
        return locale;
    }

    public void setLocale(Locale locale) {
        this.locale = locale;
    }

    @Override
    public URI uri(String identifier) {
        return applicationUris.get(identifier);
    }

    @Override
    public URI uri(String identifier, Map<String, Object> params) {
        return applicationUris.get(identifier, params);
    }

    @Override
    public UriBuilder uriBuilder(String identifier) {
        return applicationUris.getUriBuilder(identifier);
    }

} @ApplicationScoped
public class BeanValidationProducer {

    private static final Logger log = Logger.getLogger(BeanValidationProducer.class.getName());

    /**
     * The ValidatorFactory should be available for injection as defined here:
     * http://beanvalidation.org/1.1/spec/#d0e11327
     */
    @Inject
    private Instance<ValidatorFactory> validatorFactoryInstance;

    /**
     * The actual ValidatorFactory to use
     */
    private ValidatorFactory validatorFactory;

    /**
     * We should be able to get a ValidatorFactory from the container in an Java EE environment.
     * However, if we don't get the factory, we will will use a default one. This is especially
     * useful for non Java EE environments and in the CDI tests
     */
    @PostConstruct
    public void init() {

        // Prefer the ValidatorFactory provided by the container
        Iterator<ValidatorFactory> iterator = validatorFactoryInstance.iterator();
        if (iterator.hasNext()) {
            this.validatorFactory = iterator.next();
        }

        // create a default factory if we didn't get one
        else {
            log.warning("Creating a ValidatorFactory because the container didn't provide one!");
            this.validatorFactory = Validation.buildDefaultValidatorFactory();
        }

    }

    @Produces
    @OzarkInternal
    @ApplicationScoped
    public ValidatorFactory produceValidationFactory() {
        return validatorFactory;
    }

} @ApplicationScoped
public class ConstraintViolationTranslator {

    private static final Logger log = Logger.getLogger(ConstraintViolationTranslator.class.getName());

    @Inject
    @OzarkInternal
    private ValidatorFactory validatorFactory;

    /**
     * Returns the human readable error message for a given {@link ConstraintViolation}.
     *
     * @param violation The violation to get the message for
     * @param locale    The desired target locale
     * @return the localized message
     */
    public String translate(ConstraintViolation<?> violation, Locale locale) {

        SimpleMessageInterpolatorContext context = new SimpleMessageInterpolatorContext(violation);

        MessageInterpolator interpolator = validatorFactory.getMessageInterpolator();

        return interpolator.interpolate(violation.getMessageTemplate(), context, locale);

    }

    /**
     * Simple implementation of {@link javax.validation.MessageInterpolator.Context} wrapping
     * a {@link ConstraintViolation}.
     */
    private static class SimpleMessageInterpolatorContext implements MessageInterpolator.Context {

        private final ConstraintViolation<?> violation;

        public SimpleMessageInterpolatorContext(ConstraintViolation<?> violation) {
            this.violation = violation;
        }

        @Override
        public ConstraintDescriptor<?> getConstraintDescriptor() {
            return violation.getConstraintDescriptor();
        }

        @Override
        public Object getValidatedValue() {
            return violation.getInvalidValue();
        }

        @Override
        public <T> T unwrap(Class<T> type) {
            throw new UnsupportedOperationException();
        }
    }

} public class MvcConverterProvider implements ParamConverterProvider {

    @Inject
    private ConverterRegistry converterRegistry;

    @Inject
    private MvcContext mvcContext;

    @Inject
    private BindingResultImpl bindingResult;

    @Override
    public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {

        MvcBinding mvcBinding = (MvcBinding) Stream.of(annotations != null ? annotations : new Annotation[0])
                .filter(a -> a.annotationType().equals(MvcBinding.class))
                .findFirst()
                .orElse(null);

        if (mvcBinding != null) {

            MvcConverter<T> mvcConverter = converterRegistry.lookup(rawType, annotations);

            if (mvcConverter != null) {

                return new ParamConverter<T>() {

                    @Override
                    public T fromString(String value) {

                        // execute the converter
                        ConverterResult<T> result = mvcConverter.convert(value, rawType, mvcContext.getLocale());

                        // register possible errors in BindingResult
                        result.getError()
                                .map(error -> new BindingErrorImpl(error, getParamName(annotations), value))
                                .ifPresent(bindingError -> bindingResult.addBindingError(bindingError));

                        // always return a value so JAX-RS continues processing the request
                        return (T) result.getValue();

                    }

                    @Override
                    public String toString(T value) {
                        throw new UnsupportedOperationException();
                    }

                };

            }

        }
        return null;

    }

    // TODO: Duplicated in ConstraintViolationUtils
    private static String getParamName(Annotation[] annotations) {
        for (Annotation annotation : annotations) {
            if (annotation instanceof QueryParam) {
                return ((QueryParam) annotation).value();
            }
            if (annotation instanceof PathParam) {
                return ((PathParam) annotation).value();
            }
            if (annotation instanceof FormParam) {
                return ((FormParam) annotation).value();
            }
            if (annotation instanceof MatrixParam) {
                return ((MatrixParam) annotation).value();
            }
            if (annotation instanceof CookieParam) {
                return ((CookieParam) annotation).value();
            }
        }
        return null;
    }
} public class AnnotatedTypeProcessor {

    private static final Logger log = Logger.getLogger(AnnotatedTypeProcessor.class.getName());

    public <T> AnnotatedType<T> getReplacement(AnnotatedType<T> originalType) {

        boolean modified = false;
        Set<AnnotatedMethod<? super T>> methods = new LinkedHashSet<>();

        for (AnnotatedMethod<? super T> originalMethod : originalType.getMethods()) {
            AnnotatedMethod<? super T> replacement = getReplacement(originalType, originalMethod);
            if (replacement != null) {
                methods.add(replacement);
                modified = true;
            } else {
                methods.add(originalMethod);
            }
        }

        if (modified) {
            return new AnnotatedTypeWrapper<T>(originalType, methods);
        }
        return null;

    }

    private <T> AnnotatedMethod<? super T> getReplacement(AnnotatedType<T> type,
                                                          AnnotatedMethod<? super T> method) {

        boolean isResourceMethod = method.getAnnotation(GET.class) != null ||
            method.getAnnotation(POST.class) != null || method.getAnnotation(PUT.class) != null ||
            method.getAnnotation(HEAD.class) != null || method.getAnnotation(DELETE.class) != null;

        boolean hasControllerAnnotation =
            method.getAnnotation(Controller.class) != null || type.getAnnotation(Controller.class) != null;

        // added to methods to intercept calls with our validation interceptor
        Set<Annotation> markerAnnotations = Collections.singleton(() -> ValidationInterceptorBinding.class);

        // drop Hibernate Validator's marker annotations to skip the native validation
        Predicate<Class> annotationBlacklist = clazz -> isHibernateValidatorMarkerAnnotation(clazz);

        if (isResourceMethod && hasControllerAnnotation) {

            log.log(Level.FINE, "Found controller method: {0}#{1}", new Object[]{
                type.getJavaClass().getName(),
                method.getJavaMember().getName()
            });

            return new AnnotatedMethodWrapper<>(method, markerAnnotations, annotationBlacklist);

        }

        return null;

    }

    private boolean isHibernateValidatorMarkerAnnotation(Class clazz) {
        /*
         * May be one of these classes depending on the exact Hibernate Validator version:
         * org.hibernate.validator.cdi.internal.interceptor.MethodValidated
         * org.hibernate.validator.internal.cdi.interceptor.MethodValidated
         */
        return clazz.getName().startsWith("org.hibernate.validator.")
                && clazz.getName().endsWith(".interceptor.MethodValidated");
    }

} @Priority(ViewEngine.PRIORITY_BUILTIN)
public class FaceletsViewEngine extends ServletViewEngine {

    /**
     * Assumes that any view that ends with {@code .xhtml} is a facelet.
     *
     * @param view the name of the view.
     * @return {@code true} if supported or {@code false} if not.
     */
    @Override
    public boolean supports(String view) {
        return view.endsWith(".xhtml");
    }

    /**
     * Forwards request to servlet container.
     *
     * @param context view engine context.
     * @throws ViewEngineException if any error occurs.
     */
    @Override
    public void processView(ViewEngineContext context) throws ViewEngineException {
        try {
            forwardRequest(context, "*.xhtml");
        } catch (ServletException | IOException e) {
            throw new ViewEngineException(e);
        }
    }
} @Priority(ViewEngine.PRIORITY_BUILTIN)
public class JspViewEngine extends ServletViewEngine {

    /**
     * Assumes that any view that ends with {@code .jsp} or {@code .jspx} is a JSP.
     *
     * @param view the name of the view.
     * @return {@code true} if supported or {@code false} if not.
     */
    @Override
    public boolean supports(String view) {
        return view.endsWith(".jsp") || view.endsWith(".jspx");
    }

    /**
     * Forwards request to servlet container.
     *
     * @param context view engine context.
     * @throws ViewEngineException if any error occurs.
     */
    @Override
    public void processView(ViewEngineContext context) throws ViewEngineException {
        try {
            forwardRequest(context, "*.jsp", "*.jspx");
        } catch (ServletException | IOException e) {
            throw new ViewEngineException(e);
        }
    }
} @ApplicationScoped
public class ViewEngineFinder {

    @Inject
    private CdiUtils cdiUtils;

    private Map<String, ViewEngine> cache = new HashMap<>();

    /**
     * Finds view engine for a viewable.
     *
     * @param viewable the viewable to be used.
     * @return selected view engine or {@code null} if none found.
     */
    public ViewEngine find(Viewable viewable) {
        Optional<ViewEngine> engine;
        final String view = viewable.getView();

        // If engine specified in viewable, use it
        final Class<? extends ViewEngine> engineClass = viewable.getViewEngine();
        if (engineClass != null) {
            engine = Optional.of(cdiUtils.newBean(engineClass));
        } else {
            // Check cache first
            engine = Optional.ofNullable(cache.get(view));

            if (!engine.isPresent()) {
                List<ViewEngine> engines = CdiUtils.getApplicationBeans(ViewEngine.class);

                // Gather set of candidates
                final Set<ViewEngine> candidates = engines.stream()
                        .filter(e -> e.supports(view)).collect(toSet());

                // Find candidate with highest priority
                engine = candidates.stream().max(
                        (e1, e2) -> {
                            final Priority p1 = getAnnotation(e1.getClass(), Priority.class);
                            final int v1 = p1 != null ? p1.value() : ViewEngine.PRIORITY_APPLICATION;
                            final Priority p2 = getAnnotation(e2.getClass(), Priority.class);
                            final int v2 = p2 != null ? p2.value() : ViewEngine.PRIORITY_APPLICATION;
                            return v1 - v2;
                        });
                // Update cache
                if (engine.isPresent()) {
                    cache.put(view, engine.get());
                }
            }
        }
        return engine.isPresent() ? engine.get() : null;
    }
} @RequestScoped
public class CsrfImpl implements Csrf {

    @Inject
    private CsrfTokenManager csrfTokenManager;

    public String getName() {
        return csrfTokenManager.getOrCreateToken().getParamName();
    }

    public String getToken() {
        return csrfTokenManager.getOrCreateToken().getValue();
    }

} @Controller
@Priority(Priorities.HEADER_DECORATOR)
public class CsrfValidateInterceptor implements ReaderInterceptor {

    private static final int BUFFER_SIZE = 4096;
    private static final String DEFAULT_CHARSET = "UTF-8";

    @Inject
    private CsrfTokenManager csrfTokenManager;

    @Inject
    private OzarkConfig ozarkConfig;

    @Context
    private ResourceInfo resourceInfo;

    @Inject
    private Messages messages;

    @Override
    public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
        // Validate if name bound or if CSRF property enabled and a POST
        final Method controller = resourceInfo.getResourceMethod();
        if (needsValidation(controller)) {

            CsrfToken token = csrfTokenManager.getToken()
                    .orElseThrow(() -> new CsrfValidationException(messages.get("CsrfFailed", "missing token")));

            // First check if CSRF token is in header
            final String csrfToken = context.getHeaders().getFirst(token.getHeaderName());
            if (token.getValue().equals(csrfToken)) {
                return context.proceed();
            }

            // Otherwise, it must be a form parameter
            final MediaType contentType = context.getMediaType();
            if (!isSupportedMediaType(contentType)) {
                throw new CsrfValidationException(messages.get("UnableValidateCsrf", context.getMediaType()));
            }

            // Ensure stream can be restored for next interceptor
            ByteArrayInputStream bais;
            final InputStream is = context.getInputStream();
            if (is instanceof ByteArrayInputStream) {
                bais = (ByteArrayInputStream) is;
            } else {
                bais = copyStream(is);
            }

            // Validate CSRF
            boolean validated = false;
            final String charset = contentType.getParameters().get("charset");
            final String entity = toString(bais, charset != null ? charset : DEFAULT_CHARSET);
            final String[] pairs = entity.split("\\&");
            for (int i = 0; i < pairs.length; i++) {
                final String[] fields = pairs[i].split("=");
                final String nn = URLDecoder.decode(fields[0], DEFAULT_CHARSET);
                // Is this the CSRF field?
                if (token.getParamName().equals(nn)) {
                    final String vv = URLDecoder.decode(fields[1], DEFAULT_CHARSET);
                    // If so then check the token
                    if (token.getValue().equals(vv)) {
                        validated = true;
                        break;
                    }
                    throw new CsrfValidationException(messages.get("CsrfFailed", "mismatching tokens"));
                }
            }
            if (!validated) {
                throw new CsrfValidationException(messages.get("CsrfFailed", "missing field"));
            }

            // Restore stream and proceed
            bais.reset();
            context.setInputStream(bais);
        }
        return context.proceed();
    }

    protected static boolean isSupportedMediaType(MediaType contentType) {
        return contentType != null &&
            contentType.isCompatible(MediaType.APPLICATION_FORM_URLENCODED_TYPE);
    }

    private ByteArrayInputStream copyStream(InputStream is) throws IOException {
        int n;
        try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            final byte[] buffer = new byte[BUFFER_SIZE];
            while ((n = is.read(buffer)) >= 0) {
                baos.write(buffer, 0, n);
            }
            return new ByteArrayInputStream(baos.toByteArray());
        }
    }

    private String toString(ByteArrayInputStream bais, String encoding) throws UnsupportedEncodingException {
        int n = 0;
        final byte[] bb = new byte[bais.available()];
        while ((n = bais.read(bb, n, bb.length - n)) >= 0); // NOPMD ignore empty while block
        bais.reset();
        return new String(bb, encoding);
    }

    /**
     * Determines if a controller method needs CSRF validation based on the config options.
     *
     * @param controller controller to inspect.
     * @return outcome of test.
     */
    private boolean needsValidation(Method controller) {
        if (controller == null || !hasAnnotation(controller, POST.class)) {
            return false;
        }
        switch (ozarkConfig.getCsrfOptions()) {
            case OFF:
                return false;
            case IMPLICIT:
                return true;
            case EXPLICIT:
                return hasAnnotation(controller, CsrfProtected.class)
                        || hasAnnotation(controller.getDeclaringClass(), CsrfProtected.class);
        }
        return false;
    }
} @ApplicationScoped
public class UriTemplateParser {

    @Inject
    MvcContext mvcContext;

    @Inject
    private ServletContext servletContext;

    @Produces
    @ApplicationScoped
    private ApplicationUris applicationUris;

    @PostConstruct
    public void init() {

        Set<Class<?>> controllerClasses =
                (Set<Class<?>>) servletContext.getAttribute(OzarkContainerInitializer.CONTROLLER_CLASSES);

        applicationUris = init(controllerClasses != null ? controllerClasses : Collections.emptySet());

    }

    ApplicationUris init(Set<Class<?>> controllers) {
        ApplicationUris uris = new ApplicationUris();
        controllers.forEach(controller ->
                Stream.of(controller.getMethods()).filter(ControllerUtils::isControllerMethod).forEach(method -> {
                    UriTemplate uriTemplate = parseMethod(method, mvcContext.getBasePath());
                    uris.register(uriTemplate, method);
                })
        );
        return uris;
    }

    /**
     * <p>Parses given method and constructs a {@link UriTemplate} containing
     * all the information found in the annotations {@link javax.ws.rs.Path},
     * {@link javax.ws.rs.QueryParam} and {@link javax.ws.rs.MatrixParam}.</p>
     */
    UriTemplate parseMethod(Method method, String basePath) {
        UriBuilder uriBuilder = UriBuilder.fromPath(basePath);
        Path controllerPath = AnnotationUtils.getAnnotation(method.getDeclaringClass(), Path.class);
        if (controllerPath != null) {
            uriBuilder.path(controllerPath.value());
        }
        Path methodPath = AnnotationUtils.getAnnotation(method, Path.class);
        if (methodPath != null) {
            uriBuilder.path(methodPath.value());
        }
        UriTemplate.Builder uriTemplateBuilder = UriTemplate.fromTemplate(uriBuilder.toTemplate());
        // Populate a List with all properties of given target and all parameters of given method
        // except for BeanParams where we need all properties of annotated type.
        List<AnnotatedElement> annotatedElements = BeanUtils.getFieldsAndAccessors(method.getDeclaringClass());
        Arrays.asList(method.getParameters()).forEach(param -> {
            if (param.isAnnotationPresent(BeanParam.class)) {
                annotatedElements.addAll(BeanUtils.getFieldsAndAccessors(param.getType()));
            } else {
                annotatedElements.add(param);
            }
        });
        annotatedElements.forEach(accessibleObject -> {
            if (accessibleObject.isAnnotationPresent(QueryParam.class)) {
                uriTemplateBuilder.queryParam(accessibleObject.getAnnotation(QueryParam.class).value());
            }
            if (accessibleObject.isAnnotationPresent(MatrixParam.class)) {
                uriTemplateBuilder.matrixParam(accessibleObject.getAnnotation(MatrixParam.class).value());
            }
        });
        return uriTemplateBuilder.build();
    }

} @ApplicationScoped
@SuppressWarnings("unchecked")
public class CdiUtils {

    @Inject
    private BeanManager beanManager;

    /**
     * Create a new CDI bean given its class. The bean is created in the context
     * defined by the scope annotation on the class.
     *
     * @param clazz CDI class.
     * @param <T>   class parameter.
     * @return newly allocated CDI bean.
     */
    @SuppressWarnings("unchecked")
    public <T> T newBean(Class<T> clazz) {
        return newBean(beanManager, clazz);
    }

    /**
     * Create a new CDI bean given its class and a bean manager. The bean is created
     * in the context defined by the scope annotation on the class.
     *
     * @param bm    The BeanManager.
     * @param clazz CDI class.
     * @param <T>   class parameter.
     * @return newly allocated CDI bean.
     */
    public static <T> T newBean(BeanManager bm, Class<T> clazz) {
        Set<Bean<?>> beans = bm.getBeans(clazz);
        final Bean<T> bean = (Bean<T>) bm.resolve(beans);
        final CreationalContext<T> ctx = bm.createCreationalContext(bean);
        return (T) bm.getReference(bean, clazz, ctx);
    }

    /**
     * @param beforeBean The BeforeBeanDiscovery.
     * @param bm         The BeanManager.
     * @param types      annotated types to register
     */
    public static void addAnnotatedTypes(BeforeBeanDiscovery beforeBean, BeanManager bm, Class<?>... types) {
        for (Class<?> type : types) {
            beforeBean.addAnnotatedType(bm.createAnnotatedType(type), type.getName());
        }
    }

    /**
     * Returns a list of CDI beans with the specified bean type and qualifiers.
     * Please note that this method supports looking up beans deployed with the application
     * even if Ozark is deployed as a container archive.
     */
    public static <T> List<T> getApplicationBeans(Class<T> type, Annotation... qualifiers) {
        BeanManager manager = getApplicationBeanManager();
        return manager.getBeans(type, qualifiers).stream()
                .map(bean -> (T) manager.getReference(bean, type, manager.createCreationalContext(bean)))
                .collect(Collectors.toList());
    }

    /**
     * Returns a single CDI bean with the given type and qualifiers. Will throw an exception if there
     * is more than one matching bean. Please note that this method supports looking up beans deployed
     * with the application even if Ozark is deployed as a container archive.
     */
    public static <T> Optional<T> getApplicationBean(Class<T> type, Annotation... qualifiers) {
        List<T> instances = getApplicationBeans(type);
        if (instances.size() == 0) {
            return Optional.empty();
        } else if (instances.size() == 1) {
            return Optional.of(instances.get(0));
        } else {
            throw new IllegalStateException("More than one CDI managed instance found of: " + type.getName());
        }
    }

    /**
     * This method returns a {@link BeanManager} which can resolve beans defined in the application.
     * In case of Glassfish the injected {@link BeanManager} doesn't work here as it only resolves
     * beans in the Ozark archive if Ozark is installed as part of the container.
     */
    public static BeanManager getApplicationBeanManager() {
        return CDI.current().getBeanManager();
    }

} @Interceptor
@ValidationInterceptorBinding
@Priority(Interceptor.Priority.LIBRARY_BEFORE)
public class ValidationInterceptor implements Serializable {

    private static final long serialVersionUID = -5804986456381504613L;

    private static final Logger log = Logger.getLogger(ValidationInterceptor.class.getName());

    @Inject
    @OzarkInternal
    private ValidatorFactory validatorFactory;

    @Inject
    private ConstraintViolationTranslator violationTranslator;

    @Inject
    private MvcContext mvcContext;

    @Inject
    private BindingResultImpl bindingResult;

    @AroundInvoke
    public Object validateMethodInvocation(InvocationContext ctx) throws Exception {

        Object resource = ctx.getTarget();
        Method method = ctx.getMethod();

        log.log(Level.FINE, "Starting validation for controller method: {0}#{1}", new Object[]{
                resource.getClass().getName(), method.getName()
        });

        Validator validator = validatorFactory.getValidator();
        ExecutableValidator executableValidator = validator.forExecutables();

        // validate controller property parameters
        processViolations(ctx,
                validator.validate(resource)
        );

        // validate controller method parameters
        processViolations(ctx,
                executableValidator.validateParameters(resource, method, ctx.getParameters())
        );

        // execute method
        Object result = ctx.proceed();

        // TODO: Does this make sense? Nobody will be able to handle these. Remove?
        processViolations(ctx,
                executableValidator.validateReturnValue(resource, method, result)
        );

        return result;

    }

    private void processViolations(InvocationContext ctx, Set<ConstraintViolation<Object>> violations) {

        // nothing to do in this case
        if (violations.isEmpty()) {
            return;
        }

        log.log(Level.FINE, "Validation found {} constraint violations...", violations.size());

        Set<ValidationError> validationErrors = new LinkedHashSet<>();

        for (ConstraintViolation<Object> violation : violations) {

            ConstraintViolationMetadata metadata = ConstraintViolations.getMetadata(violation);

            // MVC bindings
            if (metadata.hasAnnotation(MvcBinding.class)) {

                String paramName = metadata.getParamName().orElse(null);
                if (paramName == null) {
                    log.log(Level.WARNING, "Cannot resolve paramName for violation: {0}", violation);
                }

                boolean hasBindingError = paramName != null && !paramName.isEmpty() &&
                        bindingResult.getErrors(paramName).size() > 0;

                // if there was a binding error, not the user's input but the default value got validated
                if (!hasBindingError) {

                    String message = violationTranslator.translate(violation, mvcContext.getLocale());

                    validationErrors.add(new ValidationErrorImpl(violation, paramName, message));

                }

            }

        }

        // update BindingResult
        if (!validationErrors.isEmpty()) {
            log.log(Level.FINE, "Adding {0} validation errors to binding result", validationErrors.size());
            bindingResult.addValidationErrors(validationErrors);
        }

    }

}
import org.mvcspec.ozark.MvcContextImpl;
import org.mvcspec.ozark.OzarkConfig;
import org.mvcspec.ozark.binding.BeanValidationProducer;
import org.mvcspec.ozark.binding.BindingResultManager;
import org.mvcspec.ozark.binding.ConstraintViolationTranslator;
import org.mvcspec.ozark.binding.convert.ConverterRegistry;
import org.mvcspec.ozark.binding.convert.MvcConverterProvider;
import org.mvcspec.ozark.cdi.types.AnnotatedTypeProcessor;
import org.mvcspec.ozark.core.*;
import org.mvcspec.ozark.engine.FaceletsViewEngine;
import org.mvcspec.ozark.engine.JspViewEngine;
import org.mvcspec.ozark.engine.ViewEngineFinder;
import org.mvcspec.ozark.event.*;
import org.mvcspec.ozark.jaxrs.JaxRsContextProducer;
import org.mvcspec.ozark.locale.DefaultLocaleResolver;
import org.mvcspec.ozark.locale.LocaleRequestFilter;
import org.mvcspec.ozark.locale.LocaleResolverChain;
import org.mvcspec.ozark.security.CsrfImpl;
import org.mvcspec.ozark.security.CsrfProtectFilter;
import org.mvcspec.ozark.security.CsrfTokenManager;
import org.mvcspec.ozark.security.CsrfValidateInterceptor;
import org.mvcspec.ozark.security.EncodersImpl;
import org.mvcspec.ozark.uri.ApplicationUris;
import org.mvcspec.ozark.uri.UriTemplateParser;
import org.mvcspec.ozark.util.CdiUtils;
import org.mvcspec.ozark.binding.validate.ValidationInterceptor;
import javax.annotation.Priority;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.*;
import javax.interceptor.Interceptor;
import javax.mvc.Controller;
import javax.mvc.RedirectScoped;
import javax.mvc.event.MvcEvent;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/*
 * Copyright © 2017 Ivar Grimstad (ivar.grimstad@gmail.com)
 *
 * 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.mvcspec.ozark.cdi;



/**
 * Class OzarkCdiExtension. Initialize redirect scope as CDI scope. Collect information
 * about all MVC events being observed by the application to optimize event creation
 * and firing.
 *
 * @author Santiago Pericas-Geertsen
 * @author Manfred Riem
 * @author Christian Kaltepoth
 */
@SuppressWarnings("unchecked")
public class OzarkCdiExtension implements Extension {

    private static final Logger log = Logger.getLogger(OzarkCdiExtension.class.getName());

    private static Set<Class<? extends MvcEvent>> observedEvents;

    private final AnnotatedTypeProcessor annotatedTypeProcessor = new AnnotatedTypeProcessor();

    /**
     * Before bean discovery.
     *
     * @param event the event.
     * @param beanManager the bean manager.
     */
    public void beforeBeanDiscovery(@Observes final BeforeBeanDiscovery event, BeanManager beanManager) {

        log.fine("Observed BeforeBeanDiscovery event, registering scopes and beans...");

        event.addScope(RedirectScoped.class, true, true);

        CdiUtils.addAnnotatedTypes(event, beanManager,