<commit_before>/***
 * Copyright (c) 2009 Caelum - www.caelum.com.br/opensource All rights reserved.
 *
 * 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 br.com.caelum.vraptor.validator.beanvalidation;

import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.validation.ConstraintViolation;
import javax.validation.MessageInterpolator;
import javax.validation.Path.Node;
import javax.validation.Path.ParameterNode;
import javax.validation.metadata.BeanDescriptor;
import javax.validation.metadata.MethodDescriptor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.com.caelum.vraptor.InterceptionException;
import br.com.caelum.vraptor.Intercepts;
import br.com.caelum.vraptor.Validator;
import br.com.caelum.vraptor.controller.ControllerMethod;
import br.com.caelum.vraptor.core.InterceptorStack;
import br.com.caelum.vraptor.core.MethodInfo;
import br.com.caelum.vraptor.http.ParameterNameProvider;
import br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor;
import br.com.caelum.vraptor.interceptor.Interceptor;
import br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor;
import br.com.caelum.vraptor.validator.ValidationMessage;

import com.google.common.base.Joiner;
import com.google.common.collect.MapMaker;

/**
 * Validate method parameters using Bean Validation. The method will be
 * intercepted if any parameter contains a Bean Validation annotation.
 *
 * @author <NAME>
 * @since 3.5.1
 */
@RequestScoped
@Intercepts(before = ExecuteMethodInterceptor.class, after = ParametersInstantiatorInterceptor.class)
public class MethodValidatorInterceptor implements Interceptor {

	private static final Logger logger = LoggerFactory.getLogger(MethodValidatorInterceptor.class);
	
	private static final ConcurrentMap<Method, Boolean> CACHE = new MapMaker().makeMap();

	private Locale locale;
	private MessageInterpolator interpolator;
	private MethodInfo methodInfo;
	private Validator validator;
	private ParameterNameProvider parameterNameProvider;

	private javax.validation.Validator bvalidator;


	@Deprecated
	public MethodValidatorInterceptor() {}

	@Inject
	public MethodValidatorInterceptor(Locale locale, MessageInterpolator interpolator, Validator validator,
			MethodInfo methodInfo, javax.validation.Validator bvalidator, ParameterNameProvider parameterNameProvider) {
		this.locale = locale;
		this.interpolator = interpolator;
		this.validator = validator;
		this.methodInfo = methodInfo;
		this.bvalidator = bvalidator;
		this.parameterNameProvider = parameterNameProvider;
	}

	/**
	 * Only accepts if method isn't parameterless and have at least one constraint.
	 */
	@Override
	public boolean accepts(ControllerMethod method) {
		if (method.getMethod().getParameterTypes().length == 0) {
			logger.debug("method {} has no parameters, skipping", method);
			return false;
		}
		
		Boolean hasConstraints = CACHE.get(method.getMethod());
		
		if (hasConstraints == null) {
			hasConstraints = methodHasConstraints(method);
			
			CACHE.put(method.getMethod(), hasConstraints);
			logger.debug("putting method {} into cache as {}", method, hasConstraints);
		}
		
		logger.debug("returning method {} from cache as {}", method, hasConstraints);
		return hasConstraints;
	}

	@Override
	public void intercept(InterceptorStack stack, ControllerMethod method, Object controllerInstance)
			throws InterceptionException {

		Set<ConstraintViolation<Object>> violations = bvalidator.forExecutables()
				.validateParameters(controllerInstance, method.getMethod(), methodInfo.getParameters());
		logger.debug("there are {} violations at method {}.", violations.size(), method);

		String[] names = violations.isEmpty() ? null
				: parameterNameProvider.parameterNamesFor(method.getMethod());

		for (ConstraintViolation<Object> v : violations) {
			BeanValidatorContext ctx = new BeanValidatorContext(v);
			String msg = interpolator.interpolate(v.getMessageTemplate(), ctx, locale);
			String category = extractCategory(names, v);
			validator.add(new ValidationMessage(msg, category));
			
			logger.debug("added message {}={} for contraint violation", msg, category);
		}

		stack.next(method, controllerInstance);
	}

	/**
	 * Returns the category for this constraint violation. By default, the category returned
	 * is the name of method, plus full path for property. You can override this method to
	 * change this behaviour.
	 */
	protected String extractCategory(String[] names, ConstraintViolation<Object> v) {
		Iterator<Node> property = v.getPropertyPath().iterator();
		property.next();
		ParameterNode parameterNode = property.next().as(ParameterNode.class);

		int index = parameterNode.getParameterIndex();
		return Joiner.on(".").join(v.getPropertyPath())
				.replace("arg" + parameterNode.getParameterIndex(), names[index]);
	}

	private boolean methodHasConstraints(ControllerMethod method) {
		BeanDescriptor bean = bvalidator.getConstraintsForClass(method.getController().getType());
		MethodDescriptor descriptor = bean.getConstraintsForMethod(method.getMethod().getName(), method.getMethod()
				.getParameterTypes());
		return descriptor != null && descriptor.hasConstrainedParameters();
	}
}
<commit_msg>Using internal hibernate validator cache<commit_after>/***
 * Copyright (c) 2009 Caelum - www.caelum.com.br/opensource All rights reserved.
 *
 * 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 br.com.caelum.vraptor.validator.beanvalidation;

import java.util.Iterator;
import java.util.Locale;
import java.util.Set;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.validation.ConstraintViolation;
import javax.validation.MessageInterpolator;
import javax.validation.Path.Node;
import javax.validation.Path.ParameterNode;
import javax.validation.metadata.BeanDescriptor;
import javax.validation.metadata.MethodDescriptor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.com.caelum.vraptor.InterceptionException;
import br.com.caelum.vraptor.Intercepts;
import br.com.caelum.vraptor.Validator;
import br.com.caelum.vraptor.controller.ControllerMethod;
import br.com.caelum.vraptor.core.InterceptorStack;
import br.com.caelum.vraptor.core.MethodInfo;
import br.com.caelum.vraptor.http.ParameterNameProvider;
import br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor;
import br.com.caelum.vraptor.interceptor.Interceptor;
import br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor;
import br.com.caelum.vraptor.validator.ValidationMessage;

import com.google.common.base.Joiner;

/**
 * Validate method parameters using Bean Validation. The method will be
 * intercepted if any parameter contains a Bean Validation annotation.
 *
 * @author <NAME> Garcia
 * @since 3.5.1
 */
@RequestScoped
@Intercepts(before = ExecuteMethodInterceptor.class, after = ParametersInstantiatorInterceptor.class)
public class MethodValidatorInterceptor implements Interceptor {

	private static final Logger logger = LoggerFactory.getLogger(MethodValidatorInterceptor.class);
	
	private Locale locale;
	private MessageInterpolator interpolator;
	private MethodInfo methodInfo;
	private Validator validator;
	private ParameterNameProvider parameterNameProvider;

	private javax.validation.Validator bvalidator;


	@Deprecated
	public MethodValidatorInterceptor() {}

	@Inject
	public MethodValidatorInterceptor(Locale locale, MessageInterpolator interpolator, Validator validator,
			MethodInfo methodInfo, javax.validation.Validator bvalidator, ParameterNameProvider parameterNameProvider) {
		this.locale = locale;
		this.interpolator = interpolator;
		this.validator = validator;
		this.methodInfo = methodInfo;
		this.bvalidator = bvalidator;
		this.parameterNameProvider = parameterNameProvider;
	}

	/**
	 * Only accepts if method isn't parameterless and have at least one constraint.
	 */
	@Override
	public boolean accepts(ControllerMethod method) {
		if (method.getMethod().getParameterTypes().length == 0) {
			logger.debug("method {} has no parameters, skipping", method);
			return false;
		}
		
		BeanDescriptor bean = bvalidator.getConstraintsForClass(method.getController().getType());
		MethodDescriptor descriptor = bean.getConstraintsForMethod(method.getMethod().getName(), method.getMethod()
				.getParameterTypes());
		
		return descriptor != null && descriptor.hasConstrainedParameters();
	}

	@Override
	public void intercept(InterceptorStack stack, ControllerMethod method, Object controllerInstance)
			throws InterceptionException {

		Set<ConstraintViolation<Object>> violations = bvalidator.forExecutables()
				.validateParameters(controllerInstance, method.getMethod(), methodInfo.getParameters());
		logger.debug("there are {} violations at method {}.", violations.size(), method);

		String[] names = violations.isEmpty() ? null
				: parameterNameProvider.parameterNamesFor(method.getMethod());

		for (ConstraintViolation<Object> v : violations) {
			BeanValidatorContext ctx = new BeanValidatorContext(v);
			String msg = interpolator.interpolate(v.getMessageTemplate(), ctx, locale);
			String category = extractCategory(names, v);
			validator.add(new ValidationMessage(msg, category));
			
			logger.debug("added message {}={} for contraint violation", msg, category);
		}

		stack.next(method, controllerInstance);
	}

	/**
	 * Returns the category for this constraint violation. By default, the category returned
	 * is the name of method, plus full path for property. You can override this method to
	 * change this behaviour.
	 */
	protected String extractCategory(String[] names, ConstraintViolation<Object> v) {
		Iterator<Node> property = v.getPropertyPath().iterator();
		property.next();
		ParameterNode parameterNode = property.next().as(ParameterNode.class);

		int index = parameterNode.getParameterIndex();
		return Joiner.on(".").join(v.getPropertyPath())
				.replace("arg" + parameterNode.getParameterIndex(), names[index]);
	}
}

{'fraction_non_alphanumeric': 0.09821348415477152, 'fraction_numerical': 0.002513690636502379, 'mean_word_length': 5.491841491841492, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1700646', 'n_tokens_mistral': 3206, 'n_tokens_neox': 3024, 'n_words': 799}