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

javax.validation.Validation Maven / Gradle / Ivy

There is a newer version: 8.0-6
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 javax.validation;

import javax.validation.bootstrap.GenericBootstrap;
import javax.validation.bootstrap.ProviderSpecificBootstrap;
import javax.validation.spi.BootstrapState;
import javax.validation.spi.ValidationProvider;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.WeakHashMap;

/**
 * Note: From Section 4.4.5 Validation of the 1.0 PFD Spec - Validation
 * implementations may only provide the following three public static methods:
 * buildDefaultValidatorFactory(), byDefaultProvider(), byProvider()
 *
 * @version $Rev$ $Date$
 */
public class Validation {

    public static ValidatorFactory buildDefaultValidatorFactory() {
        return byDefaultProvider().configure().buildValidatorFactory();
    }

    public static GenericBootstrap byDefaultProvider() {
        return new GenericBootstrapImpl();
    }

    public static , U extends ValidationProvider>
            ProviderSpecificBootstrap byProvider(Class providerType) {
        return new ProviderSpecificBootstrapImpl<>(providerType);
    }

    /*
     * (non-Javadoc) See Section 4.4.5 Validation - Must be private
     *
     * Geronimo implementation specific code.
     */
    private static class ProviderSpecificBootstrapImpl, U extends ValidationProvider>
        implements ProviderSpecificBootstrap {

        private final Class providerClass;
        private ValidationProviderResolver vpResolver;

        /*
         * (non-Javadoc)
         *
         * @see javax.validation.bootstrap.ProviderSpecificBootstrap#ProviderSpecificBootstrap(Class)
         */

        public ProviderSpecificBootstrapImpl(Class validationProviderClass) {
            providerClass = validationProviderClass;
        }

        /*
         * (non-Javadoc)
         *
         * @see javax.validation.bootstrap.ProviderSpecificBootstrap#providerResolver(javax.validation.ValidationProviderResolver)
         */
        public ProviderSpecificBootstrap providerResolver(ValidationProviderResolver resolver) {
            vpResolver = resolver;
            return this;
        }

        /*
         * (non-Javadoc)
         *
         * @see javax.validation.bootstrap.ProviderSpecificBootstrap#configure()
         */
        public T configure() {
            if (providerClass == null) {
                throw new ValidationException("No resolver provided");
            }

            // create a default resolver if not supplied by providerResolver()
            GenericBootstrapImpl impl = new GenericBootstrapImpl();
            if ( vpResolver == null ) {
                vpResolver = impl.getDefaultValidationProviderResolver();
            } else {
                impl.providerResolver(vpResolver);
            }

            // check each provider discovered by the resolver
            for (ValidationProvider vProvider : vpResolver.getValidationProviders()) {
                if (providerClass.isAssignableFrom(vProvider.getClass())) {
                    // Create a ValidationProvider from the above bootstrap impl
                    // and configurationType
                    return providerClass.cast(vProvider).createSpecializedConfiguration(impl);
                }
            }

            // throw a Spec required exception
            throw new ValidationException("No provider found for " + providerClass);
        }
    }

    /*
     * (non-Javadoc) See Section 4.4.5 Validation - Must be private
     *
     * Geronimo implementation specific code.
     */
    private static class GenericBootstrapImpl implements GenericBootstrap, BootstrapState {

        private ValidationProviderResolver vpDefaultResolver;
        private ValidationProviderResolver vpResolver;

        /*
         * (non-Javadoc)
         *
         * @see javax.validation.bootstrap.GenericBootstrap#providerResolver(javax.validation.ValidationProviderResolver)
         */
        public GenericBootstrap providerResolver(ValidationProviderResolver resolver) {
            vpResolver = resolver;
            return this;
        }

        /*
         * (non-Javadoc)
         *
         * @see javax.validation.spi.BootstrapState#getValidationProviderResolver()
         */
        public ValidationProviderResolver getValidationProviderResolver() {
            return vpResolver;
        }

        /*
         * (non-Javadoc)
         *
         * @see javax.validation.spi.BootstrapState#getDefaultValidationProviderResolver()
         */
        public ValidationProviderResolver getDefaultValidationProviderResolver() {
            if (vpDefaultResolver == null) {
                vpDefaultResolver = new DefaultValidationProviderResolver();
            }
            return vpDefaultResolver;
        }

        /*
         * (non-Javadoc)
         *
         * @see javax.validation.bootstrap.GenericBootstrap#configure()
         */
        public Configuration configure() {
            ValidationProviderResolver resolv = vpResolver;
            try {
                if (resolv == null) {
                    resolv = getDefaultValidationProviderResolver();
                }
                return resolv.getValidationProviders().get(0).createGenericConfiguration(this);
            } catch (Exception e) {
                throw new ValidationException("Could not create Configuration.", e);
            }
        }
    }

    /*
     * (non-Javadoc) See Section 4.4.5 Validation - Must be private
     *
     * Geronimo implementation specific code.
     */
    private static class DefaultValidationProviderResolver implements ValidationProviderResolver {
        // cache of providers per class loader
        private volatile WeakHashMap>> providerCache = new WeakHashMap<>();

        /*
         * (non-Javadoc)
         *
         * @see javax.validation.ValidationProviderResolver#getValidationProviders()
         */
        public List> getValidationProviders() {
            List> providers;

            // get our class loader
            ClassLoader cl = PrivClassLoader.get(null);
            if (cl == null) {
                cl = PrivClassLoader.get(DefaultValidationProviderResolver.class);
            }

            // use any previously cached providers
            providers = providerCache.get(cl);
            if (providers == null) {
                // need to discover and load them for this class loader
                providers = new ArrayList<>();
                ClassLoader original = Thread.currentThread().getContextClassLoader();
                try {
                    Thread.currentThread().setContextClassLoader(cl);
                    for (ValidationProvider validationProvider : ServiceLoader.load(ValidationProvider.class)) {
                        providers.add(validationProvider);
                    }
                } catch (ClassCastException e) {
                    throw new ValidationException("Invalid provider definition", e);
                } catch (Exception e) {
                    throw new ValidationException("Failed to instantiate provider", e);
                }
                finally {
                    Thread.currentThread().setContextClassLoader(original);
                }

                // cache the discovered providers
                providerCache.put(cl, providers);
            }

            // caller must handle the case of no providers found
            return providers;
        }

        private static class PrivClassLoader implements PrivilegedAction {
            private final Class c;

            public static ClassLoader get(Class c) {
                final PrivClassLoader action = new PrivClassLoader(c);
                if (System.getSecurityManager() == null) {
                    return action.run();
                }
                return AccessController.doPrivileged(action);
            }

            private PrivClassLoader(Class c) {
                this.c = c;
            }

            public ClassLoader run() {
                if (c == null) {
                    return Thread.currentThread().getContextClassLoader();
                }
                return c.getClassLoader();
            }
        }
    }
}