All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.bval.jsr.ConfigurationImpl Maven / Gradle / Ivy

There is a newer version: 10.0.0-M3
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.bval.jsr;

import java.io.Closeable;
import java.io.InputStream;
import java.time.Clock;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;

import javax.validation.BootstrapConfiguration;
import javax.validation.ClockProvider;
import javax.validation.ConstraintValidatorFactory;
import javax.validation.MessageInterpolator;
import javax.validation.ParameterNameProvider;
import javax.validation.TraversableResolver;
import javax.validation.ValidationException;
import javax.validation.ValidationProviderResolver;
import javax.validation.ValidatorFactory;
import javax.validation.spi.BootstrapState;
import javax.validation.spi.ConfigurationState;
import javax.validation.spi.ValidationProvider;
import javax.validation.valueextraction.ValueExtractor;

import org.apache.bval.jsr.parameter.DefaultParameterNameProvider;
import org.apache.bval.jsr.resolver.DefaultTraversableResolver;
import org.apache.bval.jsr.util.IOs;
import org.apache.bval.jsr.valueextraction.ValueExtractors;
import org.apache.bval.jsr.xml.ValidationParser;
import org.apache.bval.util.CloseableAble;
import org.apache.bval.util.Exceptions;
import org.apache.bval.util.Lazy;
import org.apache.bval.util.reflection.Reflection;
import org.apache.commons.weaver.privilizer.Privileged;

/**
 * Description: used to configure apache-validation for jsr.
 * Implementation of Configuration that also implements ConfigurationState,
 * hence this can be passed to buildValidatorFactory(ConfigurationState).
 * 
*/ public class ConfigurationImpl implements ApacheValidatorConfiguration, ConfigurationState, CloseableAble { private class LazyParticipant extends Lazy { private boolean locked; private LazyParticipant(Supplier init) { super(init); } ConfigurationImpl override(T value) { if (value != null) { synchronized (this) { if (!locked) { try { reset(() -> value); } finally { ConfigurationImpl.this.prepared = false; } } } } return ConfigurationImpl.this; } synchronized ConfigurationImpl externalOverride(T value) { locked = false; try { return override(value); } finally { locked = true; } } } /** * Configured {@link ValidationProvider} */ //couldn't this be parameterized or ? private final ValidationProvider provider; /** * Configured {@link ValidationProviderResolver} */ private final ValidationProviderResolver providerResolver; /** * Configured {@link ValidationProvider} class */ private Class> providerClass; private final MessageInterpolator defaultMessageInterpolator = new DefaultMessageInterpolator(); private final LazyParticipant messageInterpolator = new LazyParticipant<>(this::getDefaultMessageInterpolator); private final ConstraintValidatorFactory defaultConstraintValidatorFactory = new DefaultConstraintValidatorFactory(); private final LazyParticipant constraintValidatorFactory = new LazyParticipant<>(this::getDefaultConstraintValidatorFactory); private final TraversableResolver defaultTraversableResolver = new DefaultTraversableResolver(); private final LazyParticipant traversableResolver = new LazyParticipant<>(this::getDefaultTraversableResolver); private final ParameterNameProvider defaultParameterNameProvider = new DefaultParameterNameProvider(); private final LazyParticipant parameterNameProvider = new LazyParticipant<>(this::getDefaultParameterNameProvider); private final ClockProvider defaultClockProvider = Clock::systemDefaultZone; private final LazyParticipant clockProvider = new LazyParticipant<>(this::getDefaultClockProvider); private final ValueExtractors bootstrapValueExtractors = ValueExtractors.EMPTY.createChild(); private final ValueExtractors valueExtractors = bootstrapValueExtractors.createChild(); private final Lazy bootstrapConfiguration = new Lazy<>(this::createBootstrapConfiguration); private final Set mappingStreams = new HashSet<>(); private final Map properties = new HashMap<>(); private boolean beforeCdi = false; private ClassLoader loader; // BEGIN DEFAULTS /** * false = dirty flag (to prevent from multiple parsing validation.xml) */ private boolean prepared = false; // END DEFAULTS private boolean ignoreXmlConfiguration = false; private ParticipantFactory participantFactory; private ValidationParser validationParser; /** * Create a new ConfigurationImpl instance. * @param aState bootstrap state * @param aProvider provider */ public ConfigurationImpl(BootstrapState aState, ValidationProvider aProvider) { Exceptions.raiseIf(aProvider == null && aState == null, ValidationException::new, "one of provider or state is required"); if (aProvider == null) { this.provider = null; if (aState.getValidationProviderResolver() == null) { providerResolver = aState.getDefaultValidationProviderResolver(); } else { providerResolver = aState.getValidationProviderResolver(); } } else { this.provider = aProvider; this.providerResolver = null; } } /** * {@inheritDoc} * Ignore data from the META-INF/validation.xml file if this * method is called. * * @return this */ @Override public ApacheValidatorConfiguration ignoreXmlConfiguration() { ignoreXmlConfiguration = true; return this; } /** * {@inheritDoc} */ @Override public ConfigurationImpl messageInterpolator(MessageInterpolator resolver) { return messageInterpolator.externalOverride(resolver); } /** * {@inheritDoc} */ @Override public ApacheValidatorConfiguration traversableResolver(TraversableResolver resolver) { return traversableResolver.externalOverride(resolver); } /** * {@inheritDoc} */ @Override public ConfigurationImpl constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) { return this.constraintValidatorFactory.externalOverride(constraintValidatorFactory); } @Override public ApacheValidatorConfiguration parameterNameProvider(ParameterNameProvider parameterNameProvider) { return this.parameterNameProvider.externalOverride(parameterNameProvider); } @Override public ApacheValidatorConfiguration clockProvider(ClockProvider clockProvider) { return this.clockProvider.externalOverride(clockProvider); } /** * {@inheritDoc} * Add a stream describing constraint mapping in the Bean Validation * XML format. * * @return this */ @Override public ApacheValidatorConfiguration addMapping(InputStream stream) { if (stream != null) { mappingStreams.add(IOs.convertToMarkableInputStream(stream)); } return this; } /** * {@inheritDoc} * Add a provider specific property. This property is equivalent to * XML configuration properties. * If we do not know how to handle the property, we silently ignore it. * * @return this */ @Override public ApacheValidatorConfiguration addProperty(String name, String value) { properties.put(name, value); return this; } @Override public MessageInterpolator getDefaultMessageInterpolator() { return defaultMessageInterpolator; } @Override public TraversableResolver getDefaultTraversableResolver() { return defaultTraversableResolver; } @Override public ConstraintValidatorFactory getDefaultConstraintValidatorFactory() { return defaultConstraintValidatorFactory; } @Override public ParameterNameProvider getDefaultParameterNameProvider() { return defaultParameterNameProvider; } @Override public ClockProvider getDefaultClockProvider() { return defaultClockProvider; } /** * {@inheritDoc} * Return a map of non type-safe custom properties. * * @return null */ @Override public Map getProperties() { return properties; } /** * {@inheritDoc} * Returns true if Configuration.ignoreXMLConfiguration() has been called. * In this case, we ignore META-INF/validation.xml * * @return true */ @Override public boolean isIgnoreXmlConfiguration() { return ignoreXmlConfiguration; } /** * {@inheritDoc} */ @Override public Set getMappingStreams() { return mappingStreams; } /** * {@inheritDoc} */ @Override public MessageInterpolator getMessageInterpolator() { return messageInterpolator.get(); } @Override public BootstrapConfiguration getBootstrapConfiguration() { return bootstrapConfiguration.get(); } /** * {@inheritDoc} * main factory method to build a ValidatorFactory * * @throws ValidationException if the ValidatorFactory cannot be built */ @Override public ValidatorFactory buildValidatorFactory() { return doBuildValidatorFactory(); } /** * {@inheritDoc} * @return the constraint validator factory of this configuration. */ @Override public ConstraintValidatorFactory getConstraintValidatorFactory() { return constraintValidatorFactory.get(); } /** * {@inheritDoc} */ @Override public TraversableResolver getTraversableResolver() { return traversableResolver.get(); } @Override public ParameterNameProvider getParameterNameProvider() { return parameterNameProvider.get(); } @Override public ClockProvider getClockProvider() { return clockProvider.get(); } @Override public ApacheValidatorConfiguration addValueExtractor(ValueExtractor extractor) { valueExtractors.add(extractor); return this; } @Override public Set> getValueExtractors() { return Collections.unmodifiableSet(new LinkedHashSet<>(valueExtractors.getValueExtractors().values())); } public void deferBootstrapOverrides() { beforeCdi = true; } public void releaseDeferredBootstrapOverrides() { if (beforeCdi) { beforeCdi = false; performBootstrapOverrides(); } } @Override public Closeable getCloseable() { if (participantFactory == null) { return () -> { }; } return participantFactory; } @Privileged private ValidatorFactory doBuildValidatorFactory() { prepare(); return Optional.> ofNullable(provider).orElseGet(this::findProvider) .buildValidatorFactory(this); } private void prepare() { if (!prepared) { applyBootstrapConfiguration(); prepared = true; } } private BootstrapConfiguration createBootstrapConfiguration() { try { if (!ignoreXmlConfiguration) { loader = Reflection.loaderFromThreadOrClass(ValidationParser.class); validationParser = new ValidationParser(loader); final BootstrapConfiguration xmlBootstrap = validationParser.processValidationConfig(getProperties().get(Properties.VALIDATION_XML_PATH), this); if (xmlBootstrap != null) { return xmlBootstrap; } } validationParser = new ValidationParser(loader = Reflection.loaderFromThreadOrClass(ApacheValidatorFactory.class)); return BootstrapConfigurationImpl.DEFAULT; } finally { participantFactory = new ParticipantFactory(loader); } } private void applyBootstrapConfiguration() { final BootstrapConfiguration bootstrapConfig = bootstrapConfiguration.get(); if (bootstrapConfig.getDefaultProviderClassName() != null) { this.providerClass = loadClass(bootstrapConfig.getDefaultProviderClassName()); } bootstrapConfig.getProperties().forEach(this::addProperty); bootstrapConfig.getConstraintMappingResourcePaths().stream().map(validationParser::open) .forEach(this::addMapping); if (!beforeCdi) { performBootstrapOverrides(); } } private void performBootstrapOverrides() { final BootstrapConfiguration bootstrapConfig = bootstrapConfiguration.get(); override(messageInterpolator, bootstrapConfig::getMessageInterpolatorClassName); override(traversableResolver, bootstrapConfig::getTraversableResolverClassName); override(constraintValidatorFactory, bootstrapConfig::getConstraintValidatorFactoryClassName); override(parameterNameProvider, bootstrapConfig::getParameterNameProviderClassName); override(clockProvider, bootstrapConfig::getClockProviderClassName); bootstrapConfig.getValueExtractorClassNames().stream().> map(participantFactory::create) .forEach(bootstrapValueExtractors::add); } @SuppressWarnings("unchecked") private Class loadClass(final String className) { try { return (Class) Class.forName(className, true, loader); } catch (final ClassNotFoundException ex) { throw new ValidationException(ex); } } private ValidationProvider findProvider() { if (providerClass == null) { return providerResolver.getValidationProviders().get(0); } final Optional> knownProvider = providerResolver.getValidationProviders().stream().filter(providerClass::isInstance).findFirst(); if (knownProvider.isPresent()) { return knownProvider.get(); } try { return providerClass.getConstructor().newInstance(); } catch (Exception e) { throw Exceptions.create(ValidationException::new, "Unable to find/create %s of type %s", ValidationProvider.class.getSimpleName(), providerClass); } } private void override(LazyParticipant participant, Supplier getClassName) { Optional.ofNullable(getClassName.get()). map(participantFactory::create).ifPresent(participant::override); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy