blob: c7f35f0266c7650a2acc36feb503d7cdcd44dd74 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 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 v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
// 05/16/2008-1.0M8 Guy Pelletier
// - 218084: Implement metadata merging functionality between mapping files
// 07/15/2008-1.0.1 Guy Pelletier
// - 240679: MappedSuperclass Id not picked when on get() method accessor
// 06/29/2009-2.0 Michael O'Brien
// - 266912: change MappedSuperclass handling in stage2 to pre process accessors
// in support of the custom descriptors holding mappings required by the Metamodel
// getClassForName is now public and referenced by MappingAccessor.getMapKeyReferenceClass()
// 11/06/2009-2.0 Guy Pelletier
// - 286317: UniqueConstraint xml element is changing (plus couple other fixes, see bug)
// 05/26/2016-2.7 Tomas Kraus
// - 494610: Session Properties map should be Map<String, Object>
package org.eclipse.persistence.internal.jpa.metadata;
import static org.eclipse.persistence.config.PersistenceUnitProperties.CANONICAL_MODEL_SUB_PACKAGE;
import static org.eclipse.persistence.config.PersistenceUnitProperties.CANONICAL_MODEL_SUB_PACKAGE_DEFAULT;
import static org.eclipse.persistence.config.PersistenceUnitProperties.CANONICAL_MODEL_PREFIX;
import static org.eclipse.persistence.config.PersistenceUnitProperties.CANONICAL_MODEL_PREFIX_DEFAULT;
import static org.eclipse.persistence.config.PersistenceUnitProperties.CANONICAL_MODEL_SUFFIX;
import static org.eclipse.persistence.config.PersistenceUnitProperties.CANONICAL_MODEL_SUFFIX_DEFAULT;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.util.Map;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedClassForName;
import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass;
import org.eclipse.persistence.internal.sessions.AbstractSession;
/**
* INTERNAL:
* Common helper methods for the metadata processing.
*
* @author Guy Pelletier
* @since TopLink EJB 3.0 Reference Implementation
*/
public class MetadataHelper {
public static final String JPA_ORM_FILE = "META-INF/orm.xml";
public static final String ECLIPSELINK_ORM_FILE = "META-INF/eclipselink-orm.xml";
private MetadataHelper() {
}
/**
* INTERNAL:
* Return the canonical name. This will apply the prefix and suffix
* qualifiers given to the canonical name. If the given prefix is null, the
* the default "" is applied. If the given suffix is null, then the default
* "_" will be applied.
*/
protected static String getCanonicalName(String name, Map<String, Object> properties) {
String prefix = (String)properties.get(CANONICAL_MODEL_PREFIX);
String suffix = (String)properties.get(CANONICAL_MODEL_SUFFIX);
// If the suffix is not specified, before defaulting it check that a
// prefix was not specified.
if (suffix == null) {
if (prefix == null) {
// No prefix, use the default
suffix = CANONICAL_MODEL_SUFFIX_DEFAULT;
} else {
// Prefix specified so just blank out the suffix.
suffix = "";
}
}
if (prefix == null) {
prefix = CANONICAL_MODEL_PREFIX_DEFAULT;
}
return prefix + name + suffix;
}
/**
* INTERNAL:
* Load a class from a given class name. (XMLEntityMappings calls this one)
*/
public static Class<?> getClassForName(String classname, ClassLoader loader) {
try {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
try {
return AccessController.doPrivileged(new PrivilegedClassForName<>(classname, true, loader));
} catch (PrivilegedActionException exception) {
throw ValidationException.unableToLoadClass(classname, exception.getException());
}
} else {
return PrivilegedAccessHelper.getClassForName(classname, true, loader);
}
} catch (ClassNotFoundException exception) {
if (classname.indexOf('$') != -1) {
String outer = classname.substring(0, classname.indexOf('$'));
Class<?> outerClass = getClassForName(outer, loader);
for (int index = 0; index < outerClass.getClasses().length; index++)
{
if (outerClass.getClasses()[index].getName().equals(classname))
{
return outerClass.getClasses()[index];
}
}
}
throw ValidationException.unableToLoadClass(classname, exception);
}
}
/**
* INTERNAL:
* Create a new instance of the class given.
*/
static Object getClassInstance(Class<?> cls) {
try {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
try {
return AccessController.doPrivileged(new PrivilegedNewInstanceFromClass(cls));
} catch (PrivilegedActionException exception) {
throw ValidationException.errorInstantiatingClass(cls, exception.getException());
}
} else {
return PrivilegedAccessHelper.newInstanceFromClass(cls);
}
} catch (IllegalAccessException exception) {
throw ValidationException.errorInstantiatingClass(cls, exception);
} catch (InstantiationException exception) {
throw ValidationException.errorInstantiatingClass(cls, exception);
}
}
/**
* INTERNAL:
* Create a new instance of the class name.
*/
static Object getClassInstance(String className, ClassLoader loader) {
return getClassInstance(getClassForName(className, loader));
}
/**
* INTERNAL:
* Helper method to return a field name from a candidate field name and a
* default field name.
*
* Requires the context from where this method is called to output the
* correct logging message when defaulting the field name.
*
* In some cases, both the name and defaultName could be "" or null,
* therefore, don't log a message and return name.
*/
public static String getName(String name, String defaultName, String context, MetadataLogger logger, Object location) {
// Check if a candidate was specified otherwise use the default.
if (name != null && ! name.equals("")) {
return name;
} else if (defaultName == null || defaultName.equals("")) {
return "";
} else {
// Log the defaulting field name based on the given context.
logger.logConfigMessage(context, location, defaultName);
return defaultName;
}
}
/**
* INTERNAL:
* Return the qualified canonical name of the given qualified class name.
* This method will check the session for a corresponding class that was
* processed during deploy. If one is not found, will build the canonical
* name applying any default package and the default suffix qualifier "_".
*/
public static String getQualifiedCanonicalName(String qualifiedName, AbstractSession session) {
String sessionStaticMetamodelClass = session.getStaticMetamodelClass(qualifiedName);
if (sessionStaticMetamodelClass == null) {
return getQualifiedCanonicalName(qualifiedName, session.getProperties());
} else {
return sessionStaticMetamodelClass;
}
}
/**
* INTERNAL:
* Return the canonical name applying any default package. This will apply
* the prefix and suffix qualifiers given to the canonical name. If the
* prefix is null, the default "" is applied. If the suffix is null, then
* the default "_" will be applied.
*/
public static String getQualifiedCanonicalName(String qualifiedName, Map<String, Object> properties) {
String packageSuffix = (String)properties.get(CANONICAL_MODEL_SUB_PACKAGE);
if (packageSuffix == null) {
packageSuffix = CANONICAL_MODEL_SUB_PACKAGE_DEFAULT;
} else {
packageSuffix = packageSuffix + ".";
}
if (qualifiedName.indexOf('.') > -1) {
String canonicalName = getCanonicalName(qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1), properties);
String pkg = qualifiedName.substring(0, qualifiedName.lastIndexOf('.') + 1);
return pkg + packageSuffix + canonicalName;
} else {
return packageSuffix + getCanonicalName(qualifiedName, properties);
}
}
/**
* INTERNAL:
* Helper method to return a string value if specified, otherwise returns
* the default value.
*/
public static Integer getValue(Integer value, Integer defaultValue) {
// Check if a candidate was specified otherwise use the default.
if (value == null) {
return defaultValue;
} else {
// TODO: log a defaulting message
return value;
}
}
/**
* INTERNAL:
* Helper method to return a string value if specified, otherwise returns
* the default value.
*/
public static String getValue(String value, String defaultValue) {
// Check if a candidate was specified otherwise use the default.
if (value != null && ! value.equals("")) {
return value;
} else {
// TODO: log a defaulting message
return defaultValue;
}
}
}