Package org.grails.core.support

Source Code of org.grails.core.support.GrailsDomainConfigurationUtil

/*
* Copyright 2004-2005 the original author or authors.
*
* 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.grails.core.support;

import grails.core.GrailsApplication;
import grails.core.GrailsClass;
import grails.core.GrailsDomainClass;
import grails.core.GrailsDomainClassProperty;
import grails.util.CollectionUtils;
import grails.util.GrailsClassUtils;
import groovy.lang.GroovyObject;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.net.URL;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

import grails.validation.Constrained;
import org.grails.core.util.ClassPropertyFetcher;
import org.grails.core.io.support.GrailsFactoriesLoader;
import grails.validation.ConstraintsEvaluator;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;

/**
* Utility methods used in configuring the Grails Hibernate integration.
*
* @author Graeme Rocher
*/
public class GrailsDomainConfigurationUtil {

    public static final String PROPERTY_NAME = "constraints";

    private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class[0];
    public static final String PROPERTIES_PROPERTY = "properties";

    public static Serializable getAssociationIdentifier(Object target, String propertyName,
            GrailsDomainClass referencedDomainClass) {

        String getterName = GrailsClassUtils.getGetterName(propertyName);

        try {
            Method m = target.getClass().getMethod(getterName, EMPTY_CLASS_ARRAY);
            Object value = m.invoke(target);
            if (value != null && referencedDomainClass != null) {
                String identifierGetter = GrailsClassUtils.getGetterName(referencedDomainClass.getIdentifier().getName());
                m = value.getClass().getDeclaredMethod(identifierGetter, EMPTY_CLASS_ARRAY);
                return (Serializable)m.invoke(value);
            }
        }
        catch (NoSuchMethodException e) {
            // ignore
        }
        catch (IllegalAccessException e) {
            // ignore
        }
        catch (InvocationTargetException e) {
            // ignore
        }
        return null;
    }

    /**
     * Configures the relationships between domain classes after they have been all loaded.
     *
     * @param domainClasses The domain classes to configure relationships for
     * @param domainMap     The domain class map
     */
    public static void configureDomainClassRelationships(GrailsClass[] domainClasses, Map<?, ?> domainMap) {

        // configure super/sub class relationships
        // and configure how domain class properties reference each other
        for (GrailsClass grailsClass : domainClasses) {
            GrailsDomainClass domainClass = (GrailsDomainClass) grailsClass;
            if (!domainClass.isRoot()) {
                Class<?> superClass = grailsClass.getClazz().getSuperclass();
                while (!superClass.equals(Object.class) && !superClass.equals(GroovyObject.class)) {
                    GrailsDomainClass gdc = (GrailsDomainClass) domainMap.get(superClass.getName());
                    if (gdc == null || gdc.getSubClasses() == null) {
                        break;
                    }

                    gdc.getSubClasses().add((GrailsDomainClass)grailsClass);
                    superClass = superClass.getSuperclass();
                }
            }
            GrailsDomainClassProperty[] props = domainClass.getPersistentProperties();

            for (GrailsDomainClassProperty prop : props) {
                if (prop != null && prop.isAssociation()) {
                    GrailsDomainClass referencedGrailsDomainClass = (GrailsDomainClass) domainMap.get(prop.getReferencedPropertyType().getName());
                    prop.setReferencedDomainClass(referencedGrailsDomainClass);
                }
            }
        }

        // now configure so that the 'other side' of a property can be resolved by the property itself
        for (GrailsClass domainClass1 : domainClasses) {
            GrailsDomainClass domainClass = (GrailsDomainClass) domainClass1;
            GrailsDomainClassProperty[] props = domainClass.getPersistentProperties();

            for (GrailsDomainClassProperty prop : props) {
                if (prop == null || !prop.isAssociation()) {
                    continue;
                }

                GrailsDomainClass referenced = prop.getReferencedDomainClass();
                if (referenced == null) {
                    continue;
                }

                boolean isOwnedBy = referenced.isOwningClass(domainClass.getClazz());
                prop.setOwningSide(isOwnedBy);
                String refPropertyName = null;
                try {
                    refPropertyName = prop.getReferencedPropertyName();
                }
                catch (UnsupportedOperationException e) {
                    // ignore (to support Hibernate entities)
                }

                if (!StringUtils.hasText(refPropertyName)) {
                    GrailsDomainClassProperty[] referencedProperties = referenced.getPersistentProperties();
                    for (GrailsDomainClassProperty referencedProp : referencedProperties) {
                        // for bi-directional circular dependencies we don't want the other side
                        // to be equal to self
                        if (prop.equals(referencedProp) && prop.isBidirectional()) {
                            continue;
                        }
                        if (isCandidateForOtherSide(domainClass, prop, referencedProp)) {
                            prop.setOtherSide(referencedProp);
                            break;
                        }
                    }
                }
                else {
                    GrailsDomainClassProperty otherSide = referenced.getPropertyByName(refPropertyName);
                    prop.setOtherSide(otherSide);
                    otherSide.setOtherSide(prop);
                }
            }
        }
    }

    private static boolean isCandidateForOtherSide(GrailsDomainClass domainClass,
            GrailsDomainClassProperty prop, GrailsDomainClassProperty referencedProp) {

        if (prop.equals(referencedProp)) return false;
        if (prop.isOneToMany() && referencedProp.isOneToMany()) return false;

        Class<?> referencedPropertyType = referencedProp.getReferencedPropertyType();
        if (referencedPropertyType == null || !referencedPropertyType.isAssignableFrom(domainClass.getClazz())) {
            return false;
        }

        Map<?, ?> mappedBy = domainClass.getMappedBy();

        Object propertyMapping = mappedBy.get(prop.getName());
        boolean mappedToDifferentProperty = propertyMapping != null && !propertyMapping.equals(referencedProp.getName());

        mappedBy = referencedProp.getDomainClass().getMappedBy();
        propertyMapping = mappedBy.get(referencedProp.getName());
        boolean mappedFromDifferentProperty = propertyMapping != null && !propertyMapping.equals(prop.getName());

        return !mappedToDifferentProperty && !mappedFromDifferentProperty;
    }

    /**
     * Returns the ORM framework's mapping file name for the specified class name.
     *
     * @param className The class name of the mapped file
     * @return The mapping file name
     */
    public static String getMappingFileName(String className) {
        return className.replaceAll("\\.", "/") + ".hbm.xml";
    }

    /**
     * Returns the association map for the specified domain class
     *
     * @param domainClass the domain class
     * @return The association map
     */
    public static Map<?, ?> getAssociationMap(Class<?> domainClass) {
        ClassPropertyFetcher cpf = ClassPropertyFetcher.forClass(domainClass);

        Map<?, ?> associationMap = cpf.getPropertyValue(GrailsDomainClassProperty.HAS_MANY, Map.class);
        if (associationMap == null) {
            associationMap = Collections.EMPTY_MAP;
        }
        return associationMap;
    }

    /**
     * Retrieves the mappedBy map for the specified class.
     *
     * @param domainClass The domain class
     * @return The mappedBy map
     */
    public static Map<?, ?> getMappedByMap(Class<?> domainClass) {
        ClassPropertyFetcher cpf = ClassPropertyFetcher.forClass(domainClass);

        Map<?, ?> mappedByMap = cpf.getPropertyValue(GrailsDomainClassProperty.MAPPED_BY, Map.class);
        if (mappedByMap == null) {
            return Collections.EMPTY_MAP;
        }
        return mappedByMap;
    }

    /**
     * Establish whether it's a basic type.
     *
     * @param prop The domain class property
     * @return true if it is basic
     */
    public static boolean isBasicType(GrailsDomainClassProperty prop) {
        return prop == null ? false : isBasicType(prop.getType());
    }

    private static final Set<String> BASIC_TYPES;
    static {
        Set<String> basics = CollectionUtils.newSet(
                boolean.class.getName(),
                long.class.getName(),
                short.class.getName(),
                int.class.getName(),
                byte.class.getName(),
                float.class.getName(),
                double.class.getName(),
                char.class.getName(),
                Boolean.class.getName(),
                Long.class.getName(),
                Short.class.getName(),
                Integer.class.getName(),
                Byte.class.getName(),
                Float.class.getName(),
                Double.class.getName(),
                Character.class.getName(),
                String.class.getName(),
                java.util.Date.class.getName(),
                Time.class.getName(),
                Timestamp.class.getName(),
                java.sql.Date.class.getName(),
                BigDecimal.class.getName(),
                BigInteger.class.getName(),
                Locale.class.getName(),
                Calendar.class.getName(),
                GregorianCalendar.class.getName(),
                java.util.Currency.class.getName(),
                TimeZone.class.getName(),
                Object.class.getName(),
                Class.class.getName(),
                byte[].class.getName(),
                Byte[].class.getName(),
                char[].class.getName(),
                Character[].class.getName(),
                Blob.class.getName(),
                Clob.class.getName(),
                Serializable.class.getName(),
                URI.class.getName(),
                URL.class.getName());
        BASIC_TYPES = Collections.unmodifiableSet(basics);
    }

    public static boolean isBasicType(Class<?> propType) {
        if (propType == null) return false;
        if (propType.isArray()) {
            return isBasicType(propType.getComponentType());
        }
        return BASIC_TYPES.contains(propType.getName());
    }

    /**
     * Checks whether is property is configurational.
     *
     * @param descriptor The descriptor
     * @return true if it is configurational
     */
    public static boolean isNotConfigurational(PropertyDescriptor descriptor) {
        final String name = descriptor.getName();
        Method readMethod = descriptor.getReadMethod();
        Method writeMethod = descriptor.getWriteMethod();

        if ((readMethod != null && Modifier.isStatic(readMethod.getModifiers()) ||
               (writeMethod != null && Modifier.isStatic(writeMethod.getModifiers())))) {
            return false;
        }

        return !Errors.class.isAssignableFrom(descriptor.getPropertyType())
                && isNotConfigurational(name);
    }

    private static final Set<String> CONFIGURATIONAL_PROPERTIES;
    static {
        Set<String> configurational = CollectionUtils.newSet(
                GrailsDomainClassProperty.META_CLASS,
                GrailsDomainClassProperty.CLASS,
                GrailsDomainClassProperty.TRANSIENT,
                GrailsDomainClassProperty.ATTACHED,
                GrailsDomainClassProperty.DIRTY,
                GrailsDomainClassProperty.DIRTY_PROPERTY_NAMES,
                GrailsDomainClassProperty.RELATES_TO_MANY,
                GrailsDomainClassProperty.HAS_MANY,
                GrailsDomainClassProperty.EVANESCENT,
                GrailsDomainClassProperty.CONSTRAINTS,
                GrailsDomainClassProperty.MAPPING_STRATEGY,
                GrailsDomainClassProperty.MAPPED_BY,
                GrailsDomainClassProperty.BELONGS_TO,
                GrailsDomainClassProperty.ERRORS,
                GrailsApplication.TRANSACTION_MANAGER_BEAN,
                GrailsApplication.DATA_SOURCE_BEAN,
                GrailsApplication.SESSION_FACTORY_BEAN,
                GrailsApplication.MESSAGE_SOURCE_BEAN,
                "applicationContext",
                PROPERTIES_PROPERTY);
        CONFIGURATIONAL_PROPERTIES = Collections.unmodifiableSet(configurational);
    }

    public static boolean isConfigurational(String name) {
        return CONFIGURATIONAL_PROPERTIES.contains(name);
    }

    public static boolean isNotConfigurational(String name) {
        return !isConfigurational(name);
    }

    /**
     * Evaluates the constraints closure to build the list of constraints
     *
     * @param instance   The instance to evaluate constraints for
     * @param properties The properties of the instance
     * @param defaultConstraints A map that defines the default constraints
     *
     * @return A Map of constraints
     *
     * @deprecated Use {@link grails.validation.ConstraintsEvaluator} instead
     */
    @Deprecated
    public static Map<String, Constrained> evaluateConstraints(Object instance,
            GrailsDomainClassProperty[] properties, Map<String, Object> defaultConstraints) {
        final Class<?> theClass = instance.getClass();
        return getConstraintMap(properties, defaultConstraints, theClass);
    }

    private static Map<String, Constrained> getConstraintMap(GrailsDomainClassProperty[] properties, Map<String, Object> defaultConstraints, Class<?> theClass) {
        ConstraintsEvaluator constraintsEvaluator = GrailsFactoriesLoader.loadFactory(ConstraintsEvaluator.class, defaultConstraints);
        if(constraintsEvaluator != null) {
            return constraintsEvaluator.evaluate(theClass, properties);
        }
        return Collections.emptyMap();
    }

    /**
     * Evaluates the constraints closure to build the list of constraints
     *
     * @param theClass  The domain class to evaluate constraints for
     * @param properties The properties of the instance
     * @param defaultConstraints A map that defines the default constraints
     *
     * @return A Map of constraints
     *
     * @deprecated Use {@link grails.validation.ConstraintsEvaluator} instead
     */
    @Deprecated
    public static Map<String, Constrained> evaluateConstraints(final Class<?> theClass,
            GrailsDomainClassProperty[] properties, Map<String, Object> defaultConstraints) {
        return getConstraintMap(properties, defaultConstraints, theClass);
    }

    /**
     * Evaluates the constraints closure to build the list of constraints.
     *
     * @param instance   The instance to evaluate constraints for
     * @param properties The properties of the instance
     * @return A Map of constraints
     *          When the bean cannot be introspected
     *
     * @deprecated Use {@link grails.validation.ConstraintsEvaluator} instead
     */
    @Deprecated
    public static Map<String, Constrained> evaluateConstraints(Object instance,
            GrailsDomainClassProperty[] properties) {
        return evaluateConstraints(instance, properties,null);
    }

    /**
     * Evaluates the constraints closure to build the list of constraints.
     *
     * @param instance   The instance to evaluate constraints for
     * @return A Map of constraints
     *          When the bean cannot be introspected
     *
     * @deprecated Use {@link grails.validation.ConstraintsEvaluator} instead
     */
    @Deprecated
    public static Map<String, Constrained> evaluateConstraints(Object instance) {
        return evaluateConstraints(instance, null, null);
    }

    /**
     * Evaluates the constraints closure to build the list of constraints
     *
     * @param theClass  The class to evaluate constraints for
     * @return A Map of constraints
     *          When the bean cannot be introspected
     *
     * @deprecated Use {@link grails.validation.ConstraintsEvaluator} instead
     */
    @Deprecated
    public static Map<String, Constrained> evaluateConstraints(Class<?> theClass) {
        return evaluateConstraints(theClass, null, null);
    }

    /**
     * Evaluates the constraints closure to build the list of constraints.
     *
     * @param theClass  The class to evaluate constraints for
     * @return A Map of constraints
     *          When the bean cannot be introspected
     *
     * @deprecated Use {@link grails.validation.ConstraintsEvaluator} instead
     */
    @Deprecated
    public static Map<String, Constrained> evaluateConstraints(Class<?> theClass,
            GrailsDomainClassProperty[] properties) {
        return evaluateConstraints(theClass, properties, null);
    }

    public static LinkedList<?> getSuperClassChain(Class<?> theClass) {
        LinkedList<Class<?>> classChain = new LinkedList<Class<?>>();
        Class<?> clazz = theClass;
        while (clazz != Object.class && clazz != null) {
            classChain.addFirst(clazz);
            clazz = clazz.getSuperclass();
        }
        return classChain;
    }
}
TOP

Related Classes of org.grails.core.support.GrailsDomainConfigurationUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.