/* * 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; import grails.core.ComponentCapableDomainClass; import grails.core.GrailsDomainClass; import grails.core.GrailsDomainClassProperty; import grails.util.GrailsNameUtils; import grails.validation.Constrained; import groovy.lang.MetaProperty; import org.grails.core.artefact.DomainClassArtefactHandler; import org.grails.core.exceptions.GrailsConfigurationException; import org.grails.core.exceptions.GrailsDomainException; import org.grails.core.exceptions.InvalidPropertyException; import org.grails.core.io.support.GrailsFactoriesLoader; import org.grails.datastore.mapping.model.MappingContext; import org.grails.datastore.mapping.model.PersistentEntity; import org.grails.datastore.mapping.model.PersistentProperty; import org.grails.datastore.mapping.model.types.Association; import org.grails.datastore.mapping.reflect.NameUtils; import org.grails.validation.discovery.ConstrainedDiscovery; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.ClassUtils; import org.springframework.validation.Validator; import java.lang.reflect.Modifier; import java.util.*; /** * Default implementation of the {@link GrailsDomainClass} interface * * @author Graeme Rocher * @since 0.1 */ @SuppressWarnings("rawtypes") @Deprecated public class DefaultGrailsDomainClass extends AbstractGrailsClass implements GrailsDomainClass, ComponentCapableDomainClass { private static final Logger log = LoggerFactory.getLogger(DefaultGrailsDomainClass.class); private GrailsDomainClassProperty identifier; private GrailsDomainClassProperty version; private GrailsDomainClassProperty[] properties; private GrailsDomainClassProperty[] persistentProperties; private Map<String, GrailsDomainClassProperty> propertyMap; private Map relationshipMap; private String mappingStrategy = GrailsDomainClass.GORM; private PersistentEntity persistentEntity; private MappingContext mappingContext; private Map<String, Constrained> constrainedProperties; private boolean propertiesInitialized; private Boolean autowire = null; /** * @param clazz * @param defaultConstraints */ public DefaultGrailsDomainClass(Class<?> clazz, Map<String, Object> defaultConstraints) { this(clazz, defaultConstraints, null); } public DefaultGrailsDomainClass(Class<?> clazz, Map<String, Object> defaultConstraints, MappingContext mappingContext) { this(clazz, mappingContext); this.mappingContext = mappingContext; } public DefaultGrailsDomainClass(Class<?> clazz, MappingContext mappingContext) { this(clazz); this.mappingContext = mappingContext; } /** * Constructor. * * @param clazz */ public DefaultGrailsDomainClass(Class<?> clazz) { super(clazz, ""); } private void initializePersistentProperties() { if (!propertiesInitialized) { verifyContextIsInitialized(); propertyMap = new LinkedHashMap<>(); PersistentProperty identity = persistentEntity.getIdentity(); if (identity != null) { identifier = new DefaultGrailsDomainClassProperty(this, persistentEntity, identity); } // First go through the properties of the class and create domain properties // populating into a map populateDomainClassProperties(); // set properties from map values persistentProperties = propertyMap.values().toArray(new GrailsDomainClassProperty[propertyMap.size()]); // if no identifier property throw exception if (identifier == null) { throw new GrailsDomainException("Identity property not found, but required in domain class [" + getFullName() + "]"); } else { propertyMap.put(identifier.getName(), identifier); } // if no version property throw exception if (version != null) { propertyMap.put(version.getName(), version); } List<MetaProperty> properties = getMetaClass().getProperties(); for (MetaProperty property : properties) { String name = property.getName(); if(!propertyMap.containsKey(name) && !NameUtils.isConfigurational(name) && !Modifier.isStatic(property.getModifiers())) { propertyMap.put(name, new MetaGrailsDomainClassProperty(this, property)); } } this.properties = propertyMap.values().toArray(new GrailsDomainClassProperty[propertyMap.size()]); } propertiesInitialized = true; } private void verifyContextIsInitialized() { if (mappingContext == null) { throw new GrailsConfigurationException("That API cannot be accessed before the spring context is initialized"); } else { if (log.isWarnEnabled()) { log.warn("The GrailsDomainClass API should no longer be used to retrieve data about domain classes. Use the mapping context API instead"); } if (persistentEntity == null) { persistentEntity = mappingContext.getPersistentEntity(this.getFullName()); if (persistentEntity == null) { throw new GrailsConfigurationException("Could not retrieve the respective entity for domain " + this.getName() + " in the mapping context API"); } } } } private void throwUnsupported() { throw new UnsupportedOperationException(this.getClass().getSimpleName() + " does not support that operation because it is a proxy for the mapping context API"); } public boolean hasSubClasses() { verifyContextIsInitialized(); return !mappingContext.getChildEntities(persistentEntity).isEmpty(); } /** * Populates the domain class properties map */ private void populateDomainClassProperties() { for (PersistentProperty property : persistentEntity.getPersistentProperties()) { GrailsDomainClassProperty grailsProperty = new DefaultGrailsDomainClassProperty(this, persistentEntity, property); if (grailsProperty.getName().equals(GrailsDomainClassProperty.VERSION)) { version = grailsProperty; } else { propertyMap.put(grailsProperty.getName(), grailsProperty); } } } /** * Retrieves the association map * * @deprecated Use {@link org.grails.datastore.mapping.model.MappingContext} API instead */ @Deprecated public Map getAssociationMap() { if (relationshipMap == null) { relationshipMap = getMergedConfigurationMap(); } return relationshipMap; } @SuppressWarnings("unchecked") private Map getMergedConfigurationMap() { verifyContextIsInitialized(); Map configurationMap = new HashMap(); PersistentEntity currentEntity = this.persistentEntity; while (currentEntity != null) { List<Association> associations = currentEntity.getAssociations(); for (Association association : associations) { PersistentEntity associatedEntity = association.getAssociatedEntity(); if (associatedEntity != null) { configurationMap.put(association.getName(), associatedEntity.getJavaClass()); } } currentEntity = currentEntity.getParentEntity(); } return configurationMap; } @Override public boolean isAutowire() { if(autowire == null) { verifyContextIsInitialized(); autowire = persistentEntity.getMapping().getMappedForm().isAutowire(); } return autowire; } public boolean isOwningClass(Class domainClass) { verifyContextIsInitialized(); return persistentEntity.isOwningEntity(mappingContext.getPersistentEntity(domainClass.getName())); } /* (non-Javadoc) * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getProperties() */ public GrailsDomainClassProperty[] getProperties() { initializePersistentProperties(); return properties; } /* (non-Javadoc) * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getIdentifier() */ public GrailsDomainClassProperty getIdentifier() { initializePersistentProperties(); return identifier; } /* (non-Javadoc) * @see grails.core.GrailsDomainClass#getVersion() */ public GrailsDomainClassProperty getVersion() { initializePersistentProperties(); return version; } public GrailsDomainClassProperty[] getPersistentProperties() { initializePersistentProperties(); return persistentProperties; } /* (non-Javadoc) * @see grails.core.GrailsDomainClass#getPropertyByName(java.lang.String) */ public GrailsDomainClassProperty getPropertyByName(String name) { GrailsDomainClassProperty persistentProperty = getPersistentProperty(name); if (persistentProperty == null) { MetaProperty metaProperty = getMetaClass().getMetaProperty(name); if (metaProperty != null) { return new MetaGrailsDomainClassProperty(this, metaProperty); } else { throw new InvalidPropertyException("No property found for name [" + name + "] for class [" + getClazz() + "]"); } } return persistentProperty; } public GrailsDomainClassProperty getPersistentProperty(String name) { initializePersistentProperties(); if (propertyMap.containsKey(name)) { return propertyMap.get(name); } int indexOfDot = name.indexOf('.'); if (indexOfDot > 0) { String basePropertyName = name.substring(0, indexOfDot); if (propertyMap.containsKey(basePropertyName)) { verifyContextIsInitialized(); PersistentProperty prop = persistentEntity.getPropertyByName(basePropertyName); PersistentEntity referencedEntity = prop.getOwner(); GrailsDomainClass referencedDomainClass = (GrailsDomainClass) grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, referencedEntity.getName()); if (referencedDomainClass != null) { String restOfPropertyName = name.substring(indexOfDot + 1); return referencedDomainClass.getPropertyByName(restOfPropertyName); } } } return null; } /* (non-Javadoc) * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getFieldName(java.lang.String) */ public String getFieldName(String propertyName) { return getPropertyByName(propertyName).getFieldName(); } /* (non-Javadoc) * @see org.grails.core.AbstractGrailsClass#getName() */ @Override public String getName() { return ClassUtils.getShortName(super.getName()); } /* (non-Javadoc) * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#isOneToMany(java.lang.String) */ public boolean isOneToMany(String propertyName) { verifyContextIsInitialized(); return getPropertyByName(propertyName).isOneToMany(); } /* (non-Javadoc) * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#isManyToOne(java.lang.String) */ public boolean isManyToOne(String propertyName) { verifyContextIsInitialized(); return getPropertyByName(propertyName).isManyToOne(); } /* (non-Javadoc) * @see grails.core.GrailsDomainClass#getRelationshipType(java.lang.String) */ public Class<?> getRelatedClassType(String propertyName) { verifyContextIsInitialized(); return persistentEntity.getPropertyByName(propertyName).getOwner().getJavaClass(); } /* (non-Javadoc) * @see grails.core.GrailsDomainClass#getPropertyName() */ @Override public String getPropertyName() { return GrailsNameUtils.getPropertyNameRepresentation(getClazz()); } /* (non-Javadoc) * @see grails.core.GrailsDomainClass#isBidirectional() */ public boolean isBidirectional(String propertyName) { verifyContextIsInitialized(); return getPropertyByName(propertyName).isBidirectional(); } /* (non-Javadoc) * @see grails.core.GrailsDomainClass#getConstraints() */ @SuppressWarnings("unchecked") public Map getConstrainedProperties() { verifyContextIsInitialized(); if(constrainedProperties == null) { ConstrainedDiscovery constrainedDiscovery = GrailsFactoriesLoader.loadFactory(ConstrainedDiscovery.class); if(constrainedDiscovery == null) { constrainedProperties = Collections.emptyMap(); } else { constrainedProperties = constrainedDiscovery.findConstrainedProperties(persistentEntity); } } return constrainedProperties; } /* (non-Javadoc) * @see grails.core.GrailsDomainClass#getValidator() */ public Validator getValidator() { verifyContextIsInitialized(); return mappingContext.getEntityValidator(persistentEntity); } /* (non-Javadoc) * @see grails.core.GrailsDomainClass#setValidator(Validator validator) */ public void setValidator(Validator validator) { verifyContextIsInitialized(); mappingContext.addEntityValidator(persistentEntity, validator); } /* (non-Javadoc) * @see grails.core.GrailsDomainClass#getMappedBy() */ public String getMappingStrategy() { return mappingStrategy; } /** * Check whether the class is a root entity * * @deprecated Use {@link org.grails.datastore.mapping.model.MappingContext} API instead */ @Deprecated @Override public boolean isRoot() { verifyContextIsInitialized(); return persistentEntity.isRoot(); } /** * Obtains a Set of subclasses * * @deprecated Use {@link org.grails.datastore.mapping.model.MappingContext} API instead */ @Deprecated @Override @SuppressWarnings("unchecked") public Set getSubClasses() { verifyContextIsInitialized(); Set<GrailsDomainClass> subClasses = new LinkedHashSet<>(); for (PersistentEntity e : mappingContext.getChildEntities(persistentEntity)) { subClasses.add((GrailsDomainClass) grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, e.getName())); } return subClasses; } @Deprecated public void refreshConstraints() { throwUnsupported(); } @Override public Map getMappedBy() { throwUnsupported(); return null; } public boolean hasPersistentProperty(String propertyName) { verifyContextIsInitialized(); return persistentEntity.getPropertyByName(propertyName) != null; } public void setMappingStrategy(String strategy) { mappingStrategy = strategy; } @Deprecated public void addComponent(GrailsDomainClass component) { throwUnsupported(); } /** * Retrieves a list of embedded components * * @deprecated Use {@link org.grails.datastore.mapping.model.MappingContext} API instead */ @Deprecated public List<GrailsDomainClass> getComponents() { verifyContextIsInitialized(); List<GrailsDomainClass> components = new ArrayList<>(); for (Association a : persistentEntity.getAssociations()) { if (a.isEmbedded()) { components.add((GrailsDomainClass) grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, a.getAssociatedEntity().getName())); } } return components; } /** * Retrieves a list of associations * * @deprecated Use {@link org.grails.datastore.mapping.model.MappingContext} API instead */ @Deprecated public List<GrailsDomainClassProperty> getAssociations() { verifyContextIsInitialized(); List<GrailsDomainClassProperty> associations = new ArrayList<>(); List<String> associationNames = new ArrayList<>(); for (Association a : persistentEntity.getAssociations()) { associationNames.add(a.getName()); } for (GrailsDomainClassProperty p : persistentProperties) { if (associationNames.contains(p.getName())) { associations.add(p); } } return associations; } }