/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.internal.jpa.parsing; import java.security.AccessController; import java.security.PrivilegedActionException; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.mappings.AggregateCollectionMapping; import org.eclipse.persistence.mappings.AggregateMapping; import org.eclipse.persistence.mappings.CollectionMapping; import org.eclipse.persistence.mappings.DatabaseMapping; import org.eclipse.persistence.mappings.DirectCollectionMapping; import org.eclipse.persistence.mappings.querykeys.ForeignReferenceQueryKey; import org.eclipse.persistence.mappings.querykeys.QueryKey; import org.eclipse.persistence.internal.queries.ContainerPolicy; import org.eclipse.persistence.internal.sessions.AbstractSession; import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; import org.eclipse.persistence.internal.security.PrivilegedClassForName; import org.eclipse.persistence.internal.helper.BasicTypeHelperImpl; /** * INTERNAL * <p><b>Purpose</b>: Implement type helper methods specified by TypeHelper. * This implementation uses Class instances to represent a type. */ public class TypeHelperImpl extends BasicTypeHelperImpl implements TypeHelper { /** The session. */ private final AbstractSession session; /** The class loader used to resolve type names. */ private final ClassLoader classLoader; /** */ public TypeHelperImpl(AbstractSession session, ClassLoader classLoader) { this.session = session; this.classLoader = classLoader; } /** Returns a type representation for the specified type name or null if * there is no such type. */ public Object resolveTypeName(String typeName) { try { if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ try { return AccessController.doPrivileged( new PrivilegedClassForName(typeName, true, classLoader)); } catch (PrivilegedActionException exception) { return null; } } else { return PrivilegedAccessHelper.getClassForName(typeName, true, classLoader); } } catch (ClassNotFoundException ex) { return null; } } /** Returns the type of the attribute with the specified name in the * specified owner class. */ public Object resolveAttribute(Object ownerClass, String attribute) { DatabaseMapping mapping = resolveAttributeMapping(ownerClass, attribute); if (mapping != null) { return getType(mapping); } QueryKey queryKey = resolveQueryKey(ownerClass, attribute); if (queryKey == null) { return null; } else if (queryKey.isForeignReferenceQueryKey()) { return ((ForeignReferenceQueryKey)queryKey).getReferenceClass(); } else { return Object.class; } } /** Returns the type of the map key for the mapping on ownerClass named attribute * Returns null if that mapping does not exist or does not contain a map key */ public Object resolveMapKey(Object ownerClass, String attribute) { Object type = null; DatabaseMapping mapping = resolveAttributeMapping(ownerClass, attribute); if (mapping.isCollectionMapping()){ ContainerPolicy cp = ((CollectionMapping)mapping).getContainerPolicy(); type = cp.getKeyType(); } return type; } /** Returns the type of the class corresponding to the specified abstract * schema type. */ public Object resolveSchema(String schemaName) { ClassDescriptor descriptor = session.getDescriptorForAlias(schemaName); return (descriptor != null) ? descriptor.getJavaClass() : null; } /** Returns the enum constant if the specified type denotes an enum type * and the specified constant denotes a constant of the enum type. */ public Object resolveEnumConstant(Object type, String constant) { Class clazz = getJavaClass(type); Object[] constants = clazz.getEnumConstants(); if (constants != null) { for (int i = 0; i < constants.length; i++) { Enum<?> enumConstant = (Enum<?>) constants[i]; if (enumConstant.name().equals(constant)) { return enumConstant; } } } return null; } /** Returns true if the specified type denotes an entity class. */ public boolean isEntityClass(Object type) { ClassDescriptor desc = getDescriptor(type); return (desc != null) && !desc.isAggregateDescriptor(); } /** Returns true if the specified type denotes an orderable type */ public boolean isOrderableType(Object type) { return !(isEntityClass(type) || isEmbeddable(type)); } /** Returns true if the specified type denotes an embedded class. */ public boolean isEmbeddable(Object type) { ClassDescriptor desc = getDescriptor(type); return (desc != null) && desc.isAggregateDescriptor(); } /** Returns true if the specified type denotes an embedded attribute. */ public boolean isEmbeddedAttribute(Object ownerClass, String attribute) { DatabaseMapping mapping = resolveAttributeMapping(ownerClass, attribute); return (mapping != null) && mapping.isAggregateObjectMapping(); } /** Returns true if the specified type denotes a simple state attribute. */ public boolean isSimpleStateAttribute(Object ownerClass, String attribute) { DatabaseMapping mapping = resolveAttributeMapping(ownerClass, attribute); return (mapping != null) && mapping.isDirectToFieldMapping(); } /** Returns true if the specified attribute denotes a single valued * or collection valued relationship attribute. */ public boolean isRelationship(Object ownerClass, String attribute) { DatabaseMapping mapping = resolveAttributeMapping(ownerClass, attribute); return (mapping != null) && mapping.isForeignReferenceMapping(); } /** Returns true if the specified attribute denotes a single valued * relationship attribute. */ public boolean isSingleValuedRelationship(Object ownerClass, String attribute) { DatabaseMapping mapping = resolveAttributeMapping(ownerClass, attribute); return (mapping != null) && mapping.isObjectReferenceMapping(); } /** Returns true if the specified attribute denotes a collection valued * relationship attribute. */ public boolean isCollectionValuedRelationship(Object ownerClass, String attribute) { DatabaseMapping mapping = resolveAttributeMapping(ownerClass, attribute); return (mapping != null) && (mapping.isOneToManyMapping() || mapping.isManyToManyMapping()); } // ===== Internal helper methods ===== /** Returns the class descriptor if the specified non-null type is a class * object. */ private ClassDescriptor getDescriptor(Object type) { ClassDescriptor desc = null; if (type instanceof Class) { desc = session.getDescriptor((Class)type); } else if (type instanceof ClassDescriptor) { desc = (ClassDescriptor)type; } return desc; } /** Returns the mapping for the specified attribute of the specified * class. The method returns null if the class is not known or if the * class does not have an attribute of the specified name. */ private DatabaseMapping resolveAttributeMapping(Object ownerClass, String attribute) { ClassDescriptor descriptor = getDescriptor(ownerClass); return (descriptor == null) ? null : descriptor.getObjectBuilder().getMappingForAttributeName(attribute); } public QueryKey resolveQueryKey(Object ownerClass, String attribute) { ClassDescriptor descriptor = getDescriptor(ownerClass); if (descriptor == null) { return null; } return descriptor.getQueryKeyNamed(attribute); } private Object getType(DatabaseMapping mapping) { if (mapping == null) { return null; } Object type = null; if (mapping.isDirectCollectionMapping()){ type = ((DirectCollectionMapping)mapping).getDirectField().getType(); if (type == null){ type = Object.class; } } else if (mapping.isAggregateCollectionMapping()) { // Return the ClassDescriptor as the type representation in case // of an embedded. This makes sure that any property or field // access of the embedded uses the correct mapping information and // not the shell of the descriptors as stored by the session. type = ((AggregateCollectionMapping)mapping).getReferenceDescriptor(); } else if (mapping.isForeignReferenceMapping()) { ClassDescriptor descriptor = mapping.getReferenceDescriptor(); type = descriptor == null ? null : descriptor.getJavaClass(); } else if (mapping.isAggregateMapping()) { // Return the ClassDescriptor as the type representation in case // of an embedded. This makes sure that any property or field // access of the embedded uses the correct mapping information and // not the shell of the descriptors as stored by the session. type = ((AggregateMapping)mapping).getReferenceDescriptor(); } else { type = mapping.getAttributeAccessor().getAttributeClass(); } return type; } }