blob: ebf5943c33bc1dd8dbaa6d2108c4f6d963a586b9 [file] [log] [blame]
/*
* Copyright (c) 1998, 2020 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:
// David McCann - 2.5.0 - Sept.18, 2012 - Initial Implementation
package org.eclipse.persistence.tools.dbws;
import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.IN;
import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.INOUT;
import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.EL_ACCESS_VIRTUAL;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_IN;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_INOUT;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_OUT;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_REF_CURSOR;
import static org.eclipse.persistence.internal.xr.XRDynamicClassLoader.COLLECTION_WRAPPER_SUFFIX;
import static org.eclipse.persistence.platform.database.oracle.plsql.OraclePLSQLTypes.PLSQLBoolean;
import static org.eclipse.persistence.platform.database.oracle.plsql.OraclePLSQLTypes.XMLType;
import static org.eclipse.persistence.tools.dbws.Util.BOOLEAN_STR;
import static org.eclipse.persistence.tools.dbws.Util.DOT;
import static org.eclipse.persistence.tools.dbws.Util.PERCENT;
import static org.eclipse.persistence.tools.dbws.Util.ROWTYPE_STR;
import static org.eclipse.persistence.tools.dbws.Util.UNDERSCORE;
import static org.eclipse.persistence.tools.dbws.Util.VARCHAR2_STR;
import static org.eclipse.persistence.tools.dbws.Util.VARCHAR_STR;
import static org.eclipse.persistence.tools.dbws.Util.XMLTYPE_STR;
import static org.eclipse.persistence.tools.dbws.Util._TYPE_STR;
import static org.eclipse.persistence.tools.dbws.Util.getGeneratedAlias;
import static org.eclipse.persistence.tools.dbws.Util.getJDBCTypeFromTypeName;
import static org.eclipse.persistence.tools.dbws.Util.getOraclePLSQLTypeForName;
import static org.eclipse.persistence.tools.dbws.Util.isArgPLSQLScalar;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.persistence.config.HintValues;
import org.eclipse.persistence.config.QueryHints;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.databaseaccess.DatabaseCall;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.ClassAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EmbeddableAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.XMLAttributes;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.BasicAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.EmbeddedAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.IdAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.MappingAccessor;
import org.eclipse.persistence.internal.jpa.metadata.columns.ColumnMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.ComplexTypeMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.NamedNativeQueryMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.NamedPLSQLStoredFunctionQueryMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.NamedPLSQLStoredProcedureQueryMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.NamedStoredFunctionQueryMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.NamedStoredProcedureQueryMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.OracleArrayTypeMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.OracleComplexTypeMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.OracleObjectTypeMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.PLSQLComplexTypeMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.PLSQLParameterMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.PLSQLRecordMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.PLSQLTableMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.QueryHintMetadata;
import org.eclipse.persistence.internal.jpa.metadata.queries.StoredProcedureParameterMetadata;
import org.eclipse.persistence.internal.jpa.metadata.structures.ArrayAccessor;
import org.eclipse.persistence.internal.jpa.metadata.structures.StructMetadata;
import org.eclipse.persistence.internal.jpa.metadata.structures.StructureAccessor;
import org.eclipse.persistence.internal.jpa.metadata.tables.TableMetadata;
import org.eclipse.persistence.internal.jpa.metadata.xml.XMLEntityMappings;
import org.eclipse.persistence.mappings.AggregateMapping;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.DirectToFieldMapping;
import org.eclipse.persistence.mappings.structures.ArrayMapping;
import org.eclipse.persistence.mappings.structures.ObjectArrayMapping;
import org.eclipse.persistence.mappings.structures.ObjectRelationalDataTypeDescriptor;
import org.eclipse.persistence.mappings.structures.ObjectRelationalDatabaseField;
import org.eclipse.persistence.mappings.structures.StructureMapping;
import org.eclipse.persistence.platform.database.oracle.plsql.PLSQLStoredFunctionCall;
import org.eclipse.persistence.platform.database.oracle.plsql.PLSQLStoredProcedureCall;
import org.eclipse.persistence.platform.database.oracle.plsql.PLSQLargument;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.StoredFunctionCall;
import org.eclipse.persistence.queries.StoredProcedureCall;
import org.eclipse.persistence.sessions.Project;
import org.eclipse.persistence.tools.oracleddl.metadata.CompositeDatabaseType;
import org.eclipse.persistence.tools.oracleddl.metadata.FieldType;
import org.eclipse.persistence.tools.oracleddl.metadata.ObjectTableType;
import org.eclipse.persistence.tools.oracleddl.metadata.ObjectType;
import org.eclipse.persistence.tools.oracleddl.metadata.PLSQLCollectionType;
import org.eclipse.persistence.tools.oracleddl.metadata.PLSQLRecordType;
import org.eclipse.persistence.tools.oracleddl.metadata.PLSQLType;
import org.eclipse.persistence.tools.oracleddl.metadata.VArrayType;
/**
* This class is responsible for generating an XMLEntityMappings instance based
* on a given OR Project's Queries and Descriptors.
*
*/
public class XmlEntityMappingsGenerator {
static final String IN_STR = "IN";
static final String INOUT_STR = "IN_OUT";
static final String OUT_STR = "OUT";
static final String CURSOR_STR = "OUT_CURSOR";
static final String ARRAYLIST_STR = "java.util.ArrayList";
static final String STRING_STR = "java.lang.String";
/**
* Generate an XMLEntityMappings instance based on a given OR Project's Queries and Descriptors.
*
* @param orProject the ORM Project instance containing Queries and Descriptors to be used to generate an XMLEntityMappings
* @param complexTypes list of composite database types used to generate metadata for advanced Oracle and PL/SQL types
* @param crudOperations map of maps keyed on table name - the second map are operation name to SQL string entries
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static XMLEntityMappings generateXmlEntityMappings(Project orProject, List<CompositeDatabaseType> complexTypes, Map<String, Map<String, String>> crudOperations) {
List<ClassDescriptor> descriptors = orProject.getOrderedDescriptors();
List<DatabaseQuery> queries = orProject.getQueries();
XMLEntityMappings xmlEntityMappings = new XMLEntityMappings();
xmlEntityMappings.setEmbeddables(new ArrayList<EmbeddableAccessor>());
xmlEntityMappings.setEntities(new ArrayList<EntityAccessor>());
xmlEntityMappings.setPLSQLRecords(new ArrayList<PLSQLRecordMetadata>());
xmlEntityMappings.setPLSQLTables(new ArrayList<PLSQLTableMetadata>());
xmlEntityMappings.setOracleObjectTypes(new ArrayList<OracleObjectTypeMetadata>());
xmlEntityMappings.setOracleArrayTypes(new ArrayList<OracleArrayTypeMetadata>());
// process PL/SQL records and collections, and Oracle advanced JDBC types
List<PLSQLRecordMetadata> plsqlRecords = null;
List<PLSQLTableMetadata> plsqlTables = null;
List<OracleObjectTypeMetadata> objectTypes = null;
List<OracleArrayTypeMetadata> arrayTypes = null;
// generate metadata for each of the composite types
List<ComplexTypeMetadata> complexTypeMetadata = processCompositeTypes(complexTypes, orProject);
for (ComplexTypeMetadata cTypeMetadata : complexTypeMetadata) {
if (cTypeMetadata.isOracleComplexTypeMetadata()) {
OracleComplexTypeMetadata octMetadata = (OracleComplexTypeMetadata) cTypeMetadata;
if (octMetadata.isOracleArrayTypeMetadata()) {
if (arrayTypes == null) {
arrayTypes = new ArrayList<OracleArrayTypeMetadata>();
}
arrayTypes.add((OracleArrayTypeMetadata) octMetadata);
} else {
// assumes OracleObjectTypeMetadata
if (objectTypes == null) {
objectTypes = new ArrayList<OracleObjectTypeMetadata>();
}
objectTypes.add((OracleObjectTypeMetadata) octMetadata);
}
} else {
// assumes PL/SQL complex type metadata
PLSQLComplexTypeMetadata plsqlctMetadata = (PLSQLComplexTypeMetadata) cTypeMetadata;
if (plsqlctMetadata.isPLSQLRecordMetadata()) {
if (plsqlRecords == null) {
plsqlRecords = new ArrayList<PLSQLRecordMetadata>();
}
plsqlRecords.add((PLSQLRecordMetadata) plsqlctMetadata);
} else {
// assumes PLSQLTableMetadata
if (plsqlTables == null) {
plsqlTables = new ArrayList<PLSQLTableMetadata>();
}
plsqlTables.add((PLSQLTableMetadata) plsqlctMetadata);
}
}
}
// add generated metadata
xmlEntityMappings.setPLSQLRecords(plsqlRecords);
xmlEntityMappings.setPLSQLTables(plsqlTables);
xmlEntityMappings.setOracleObjectTypes(objectTypes);
xmlEntityMappings.setOracleArrayTypes(arrayTypes);
// process stored procedures/functions
List<NamedPLSQLStoredProcedureQueryMetadata> plsqlStoredProcs = null;
List<NamedPLSQLStoredFunctionQueryMetadata> plsqlStoredFuncs = null;
List<NamedStoredProcedureQueryMetadata> storedProcs = null;
List<NamedStoredFunctionQueryMetadata> storedFuncs = null;
List<NamedNativeQueryMetadata> namedNativeQueries = null;
// process database queries set on the descriptor
for (DatabaseQuery query : queries) {
if (query.getCall().isStoredFunctionCall()) {
if (query.getCall() instanceof PLSQLStoredFunctionCall) {
PLSQLStoredFunctionCall call = (PLSQLStoredFunctionCall)query.getCall();
NamedPLSQLStoredFunctionQueryMetadata metadata = new NamedPLSQLStoredFunctionQueryMetadata();
metadata.setName(query.getName());
metadata.setProcedureName(call.getProcedureName());
List<PLSQLParameterMetadata> params = new ArrayList<PLSQLParameterMetadata>();
if (plsqlStoredFuncs == null) {
plsqlStoredFuncs = new ArrayList<NamedPLSQLStoredFunctionQueryMetadata>();
}
PLSQLargument arg;
PLSQLParameterMetadata param;
List<PLSQLargument> types = call.getArguments();
for (int i=0; i < types.size(); i++) {
arg = types.get(i);
param = new PLSQLParameterMetadata();
param.setName(arg.name);
String dbType = arg.databaseType.getTypeName();
if (arg.databaseType == XMLType) {
dbType = XMLType.name();
} else if (arg.databaseType == PLSQLBoolean) {
dbType = PLSQLBoolean.name();
} else {
if (!(getJDBCTypeFromTypeName(dbType) == Types.OTHER)) {
dbType = dbType.concat(_TYPE_STR);
}
}
param.setDatabaseType(dbType);
if (i == 0) {
// first arg is the return arg
metadata.setReturnParameter(param);
if (arg.cursorOutput) {
param.setDirection(CURSOR_STR);
}
} else {
param.setDirection(getDirectionAsString(arg.direction));
params.add(param);
}
}
if (params.size() > 0) {
metadata.setParameters(params);
}
plsqlStoredFuncs.add(metadata);
} else {
StoredFunctionCall call = (StoredFunctionCall)query.getCall();
NamedStoredFunctionQueryMetadata metadata = new NamedStoredFunctionQueryMetadata();
metadata.setName(query.getName());
metadata.setProcedureName(call.getProcedureName());
List<StoredProcedureParameterMetadata> params = new ArrayList<StoredProcedureParameterMetadata>();
if (storedFuncs == null) {
storedFuncs = new ArrayList<NamedStoredFunctionQueryMetadata>();
}
DatabaseField arg;
StoredProcedureParameterMetadata param;
List<DatabaseField> paramFields = call.getParameters();
List<Integer> types = call.getParameterTypes();
for (int i=0; i < paramFields.size(); i++) {
arg = paramFields.get(i);
param = new StoredProcedureParameterMetadata();
param.setTypeName(arg.getTypeName());
if (arg.getSqlType() != DatabaseField.NULL_SQL_TYPE) {
param.setJdbcType(arg.getSqlType());
}
if (arg.isObjectRelationalDatabaseField()) {
param.setJdbcTypeName(((ObjectRelationalDatabaseField)arg).getSqlTypeName());
}
if (i == 0) {
// first arg is the return arg
metadata.setReturnParameter(param);
// handle CURSOR types - want name/value pairs returned
if (types.get(i) == 8) {
addQueryHint(metadata);
}
} else {
param.setName(arg.getName());
param.setMode(getParameterModeAsString(types.get(i)));
params.add(param);
}
}
if (params.size() > 0) {
metadata.setParameters(params);
}
storedFuncs.add(metadata);
}
} else if (query.getCall().isStoredProcedureCall()) {
if (query.getCall() instanceof PLSQLStoredProcedureCall) {
PLSQLStoredProcedureCall call = (PLSQLStoredProcedureCall)query.getCall();
if (plsqlStoredProcs == null) {
plsqlStoredProcs = new ArrayList<NamedPLSQLStoredProcedureQueryMetadata>();
}
NamedPLSQLStoredProcedureQueryMetadata metadata = new NamedPLSQLStoredProcedureQueryMetadata();
metadata.setName(query.getName());
metadata.setProcedureName(call.getProcedureName());
PLSQLParameterMetadata param;
List<PLSQLParameterMetadata> params = new ArrayList<PLSQLParameterMetadata>();
List<PLSQLargument> types = call.getArguments();
for (PLSQLargument arg : types) {
param = new PLSQLParameterMetadata();
param.setName(arg.name);
String dbType = processTypeName(arg.databaseType.getTypeName());
if (arg.cursorOutput) {
param.setDirection(CURSOR_STR);
} else {
param.setDirection(getDirectionAsString(arg.direction));
}
if (arg.databaseType == XMLType) {
param.setDatabaseType(XMLType.name());
} else if (arg.databaseType == PLSQLBoolean) {
param.setDatabaseType(PLSQLBoolean.name());
} else {
param.setDatabaseType(dbType);
}
params.add(param);
}
if (params.size() > 0) {
metadata.setParameters(params);
}
plsqlStoredProcs.add(metadata);
} else {
StoredProcedureCall call = (StoredProcedureCall) query.getCall();
NamedStoredProcedureQueryMetadata metadata = new NamedStoredProcedureQueryMetadata();
metadata.setName(query.getName());
metadata.setProcedureName(call.getProcedureName());
metadata.setReturnsResultSet(false);
List<StoredProcedureParameterMetadata> params = new ArrayList<StoredProcedureParameterMetadata>();
DatabaseField arg;
StoredProcedureParameterMetadata param;
List paramFields = call.getParameters();
List<Integer> types = call.getParameterTypes();
for (int i = 0; i < paramFields.size(); i++) {
if (types.get(i) == DatabaseCall.INOUT) {
// for INOUT we get Object[IN, OUT]
arg = (DatabaseField) ((Object[]) paramFields.get(i))[1];
} else {
arg = (DatabaseField) paramFields.get(i);
}
param = new StoredProcedureParameterMetadata();
param.setName(arg.getName());
param.setTypeName(arg.getTypeName());
if (arg.getSqlType() != DatabaseField.NULL_SQL_TYPE) {
param.setJdbcType(arg.getSqlType());
}
if (arg.isObjectRelationalDatabaseField()) {
param.setJdbcTypeName(((ObjectRelationalDatabaseField) arg).getSqlTypeName());
}
param.setMode(getParameterModeAsString(types.get(i)));
// handle CURSOR types - want name/value pairs returned
if (types.get(i) == 8) {
addQueryHint(metadata);
}
params.add(param);
}
if (params.size() > 0) {
metadata.setParameters(params);
}
if (storedProcs == null) {
storedProcs = new ArrayList<NamedStoredProcedureQueryMetadata>();
}
storedProcs.add(metadata);
}
} else {
// named native query
NamedNativeQueryMetadata namedQuery = new NamedNativeQueryMetadata();
namedQuery.setName(query.getName());
namedQuery.setQuery(query.getSQLString());
namedQuery.setResultClassName(query.getReferenceClassName());
if (namedNativeQueries == null) {
namedNativeQueries = new ArrayList<NamedNativeQueryMetadata>();
}
namedNativeQueries.add(namedQuery);
}
}
// add generated metadata
if (plsqlStoredProcs != null) {
xmlEntityMappings.setNamedPLSQLStoredProcedureQueries(plsqlStoredProcs);
}
if (plsqlStoredFuncs != null) {
xmlEntityMappings.setNamedPLSQLStoredFunctionQueries(plsqlStoredFuncs);
}
if (storedProcs != null) {
xmlEntityMappings.setNamedStoredProcedureQueries(storedProcs);
}
if (storedFuncs != null) {
xmlEntityMappings.setNamedStoredFunctionQueries(storedFuncs);
}
if (namedNativeQueries != null) {
xmlEntityMappings.setNamedNativeQueries(namedNativeQueries);
}
// generate a ClassAccessor for each Descriptor, keeping track of Embeddables
List<String> embeddables = new ArrayList<String>();
Map<String, ClassAccessor> accessors = new HashMap<String, ClassAccessor>();
for (ClassDescriptor cdesc : descriptors) {
boolean embeddable = false;
ClassAccessor classAccessor;
if (cdesc.isAggregateDescriptor()) {
embeddable = true;
classAccessor = new EmbeddableAccessor();
embeddables.add(cdesc.getJavaClassName());
} else {
classAccessor = new EntityAccessor();
}
classAccessor.setClassName(cdesc.getJavaClassName());
classAccessor.setAccess(EL_ACCESS_VIRTUAL);
// may need add STRUCT metadata to the classAccessor to ensure correct field ordering
if (cdesc.isObjectRelationalDataTypeDescriptor()) {
ObjectRelationalDataTypeDescriptor odesc = (ObjectRelationalDataTypeDescriptor) cdesc;
if (odesc.getOrderedFields().size() > 0) {
StructMetadata struct = new StructMetadata();
struct.setName(odesc.getStructureName());
struct.setFields(odesc.getOrderedFields());
classAccessor.setStruct(struct);
}
}
if (!embeddable && cdesc.getTableName() != null) {
TableMetadata table = new TableMetadata();
table.setName(cdesc.getTableName());
((EntityAccessor)classAccessor).setTable(table);
}
if (!embeddable) {
List<NamedNativeQueryMetadata> namedNatQueries = new ArrayList<NamedNativeQueryMetadata>();
NamedNativeQueryMetadata namedQuery;
DatabaseQuery dbQuery;
// process findAll and findByPk queries
for (Iterator<DatabaseQuery> queryIt = cdesc.getQueryManager().getAllQueries().iterator(); queryIt.hasNext();) {
dbQuery = queryIt.next();
namedQuery = new NamedNativeQueryMetadata();
namedQuery.setName(dbQuery.getName());
namedQuery.setQuery(dbQuery.getSQLString());
namedQuery.setResultClassName(dbQuery.getReferenceClassName());
namedNatQueries.add(namedQuery);
}
// now create/update/delete operations
Map<String, String> crudOps = crudOperations.get(cdesc.getTableName());
if (!crudOps.isEmpty()) {
for (String opName : crudOps.keySet()) {
String crudSql = crudOps.get(opName);
NamedNativeQueryMetadata crudQuery = new NamedNativeQueryMetadata();
crudQuery.setName(opName);
crudQuery.setQuery(crudSql);
namedNatQueries.add(crudQuery);
}
}
if (namedNatQueries.size() > 0) {
((EntityAccessor)classAccessor).setNamedNativeQueries(namedNatQueries);
}
}
classAccessor.setAttributes(new XMLAttributes());
classAccessor.getAttributes().setIds(new ArrayList<IdAccessor>());
classAccessor.getAttributes().setBasics(new ArrayList<BasicAccessor>());
classAccessor.getAttributes().setArrays(new ArrayList<ArrayAccessor>());
classAccessor.getAttributes().setStructures(new ArrayList<StructureAccessor>());
classAccessor.getAttributes().setEmbeddeds(new ArrayList<EmbeddedAccessor>());
if (embeddable) {
xmlEntityMappings.getEmbeddables().add((EmbeddableAccessor) classAccessor);
} else {
xmlEntityMappings.getEntities().add((EntityAccessor) classAccessor);
}
accessors.put(cdesc.getJavaClassName(), classAccessor);
}
// now the we know what the embeddables are, we can process mappings
for (ClassDescriptor cdesc : descriptors) {
ClassAccessor classAccessor = accessors.get(cdesc.getJavaClassName());
MappingAccessor mapAccessor;
// generate a MappingAccessor for each mapping
for (DatabaseMapping dbMapping : cdesc.getMappings()) {
mapAccessor = generateMappingAccessor(dbMapping, embeddables);
if (mapAccessor == null) {
continue;
}
if (mapAccessor.isId()) {
classAccessor.getAttributes().getIds().add((IdAccessor) mapAccessor);
} else if (mapAccessor.isBasic()) {
classAccessor.getAttributes().getBasics().add((BasicAccessor) mapAccessor);
} else if (mapAccessor instanceof ArrayAccessor) {
classAccessor.getAttributes().getArrays().add((ArrayAccessor) mapAccessor);
} else if (mapAccessor instanceof StructureAccessor) {
classAccessor.getAttributes().getStructures().add((StructureAccessor) mapAccessor);
} else { // assumes EmbeddedAccessor
classAccessor.getAttributes().getEmbeddeds().add((EmbeddedAccessor) mapAccessor);
}
}
}
return xmlEntityMappings;
}
/**
* Process a given DatabaseMapping and return a MappingAccessor.
*
* Expected mappings are:
* <ul>
* <li>org.eclipse.persistence.mappings.DirectToFieldMapping
* <li>org.eclipse.persistence.mappings.structures.ArrayMapping
* <li>org.eclipse.persistence.mappings.structures.ObjectArrayMapping
* <li>org.eclipse.persistence.mappings.structures.StructureMapping
* </ul>
*/
protected static MappingAccessor generateMappingAccessor(DatabaseMapping mapping, List<String> embeddables) {
MappingAccessor mapAccessor = null;
if (mapping.isDirectToFieldMapping()) {
mapAccessor = processDirectMapping((DirectToFieldMapping) mapping);
} else if (mapping instanceof ObjectArrayMapping) {
mapAccessor = processObjectArrayMapping((ObjectArrayMapping) mapping);
} else if (mapping instanceof ArrayMapping) {
mapAccessor = processArrayMapping((ArrayMapping) mapping);
} else if (mapping.isStructureMapping()) {
mapAccessor = processStructureMapping((StructureMapping) mapping);
} else if (embeddables.contains(((AggregateMapping) mapping).getReferenceClassName())) {
mapAccessor = processEmbeddedMapping((AggregateMapping) mapping);
}
return mapAccessor;
}
/**
* Generate a MappingAccessor for a given DirectToFieldMapping.
*
*/
protected static BasicAccessor processDirectMapping(DirectToFieldMapping mapping) {
BasicAccessor directMapping;
if (mapping.getDescriptor().getPrimaryKeyFields().contains(mapping.getField())) {
directMapping = new IdAccessor();
} else {
directMapping = new BasicAccessor();
}
directMapping.setName(mapping.getAttributeName());
directMapping.setAttributeType(mapping.getAttributeClassificationName());
ColumnMetadata column = new ColumnMetadata();
column.setName(mapping.getField().getName());
directMapping.setColumn(column);
return directMapping;
}
/**
* Generate a MappingAccessor for a given ArrayMapping.
*
*/
protected static ArrayAccessor processArrayMapping(ArrayMapping mapping) {
ArrayAccessor arrayAccessor = new ArrayAccessor();
arrayAccessor.setName(mapping.getAttributeName());
arrayAccessor.setDatabaseType(mapping.getStructureName());
arrayAccessor.setAttributeType(ARRAYLIST_STR);
arrayAccessor.setTargetClassName(mapping.getStructureName());
ColumnMetadata column = new ColumnMetadata();
column.setName(mapping.getField().getName());
arrayAccessor.setColumn(column);
return arrayAccessor;
}
/**
* Generate a MappingAccessor for a given ObjectArrayMapping.
*
*/
protected static ArrayAccessor processObjectArrayMapping(ObjectArrayMapping mapping) {
ArrayAccessor arrayAccessor = new ArrayAccessor();
arrayAccessor.setName(mapping.getAttributeName());
arrayAccessor.setDatabaseType(mapping.getStructureName());
arrayAccessor.setTargetClassName(mapping.getReferenceClassName());
arrayAccessor.setAttributeType(ARRAYLIST_STR);
ColumnMetadata column = new ColumnMetadata();
column.setName(mapping.getField().getName());
arrayAccessor.setColumn(column);
return arrayAccessor;
}
/**
* Generate a MappingAccessor for a given StructureMapping.
*
*/
protected static StructureAccessor processStructureMapping(StructureMapping mapping) {
StructureAccessor structAccessor = new StructureAccessor();
structAccessor.setName(mapping.getAttributeName());
structAccessor.setTargetClassName(mapping.getReferenceClassName());
structAccessor.setAttributeType(mapping.getReferenceClassName());
ColumnMetadata column = new ColumnMetadata();
column.setName(mapping.getField().getName());
structAccessor.setColumn(column);
return structAccessor;
}
/**
* Generate an EmbeddedAccessor for a given AggregateMapping.
*
*/
protected static EmbeddedAccessor processEmbeddedMapping(AggregateMapping mapping) {
EmbeddedAccessor embeddedAccessor = new EmbeddedAccessor();
embeddedAccessor.setName(mapping.getAttributeName());
embeddedAccessor.setAttributeType(mapping.getReferenceClassName());
return embeddedAccessor;
}
/**
* Return a parameter direction as a String based on a given in value.
*
* Expected 'direction' value is one of:
* <ul>
* <li>org.eclipse.persistence.internal.databaseaccess.DatasourceCall.IN
* <li>org.eclipse.persistence.internal.databaseaccess.DatasourceCall.INOUT
* <li>org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT
* <li>org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT_CURSOR
* </ul>
*
*/
public static String getDirectionAsString(int direction) {
if (direction == IN) {
return IN_STR;
}
if (direction == OUT) {
return OUT_STR;
}
if (direction == INOUT) {
return INOUT_STR;
}
return CURSOR_STR;
}
/**
* Return a parameter mode as a String based on a given in value.
*
* Expected 'direction' value is one of:
* <ul>
* <li>org.eclipse.persistence.internal.databaseaccess.DatasourceCall.IN
* <li>org.eclipse.persistence.internal.databaseaccess.DatasourceCall.INOUT
* <li>org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT
* <li>org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT_CURSOR
* </ul>
*
* Will return one of:
* <ul>
* <li>org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_IN
* <li>org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_INOUT
* <li>org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_OUT
* <li>org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_REF_CURSOR
* </ul>
*/
public static String getParameterModeAsString(int direction) {
if (direction == IN) {
return JPA_PARAMETER_IN;
}
if (direction == OUT) {
return JPA_PARAMETER_OUT;
}
if (direction == INOUT) {
return JPA_PARAMETER_INOUT;
}
return JPA_PARAMETER_REF_CURSOR;
}
/**
* Alter the given type name if required.
*/
protected static String processTypeName(String typeName) {
if (!(getJDBCTypeFromTypeName(typeName) == Types.OTHER)) {
// OR Metadata doesn't handle VARCHAR2
if (typeName.equals(VARCHAR2_STR)) {
typeName = VARCHAR_STR;
}
// for BOOLEAN we want to wrap the type in a PLSQLrecord (in ORMetadata.getDatabaseTypeEnum) to
// force the appropriate conversion method in PLSQLStoredProcedureCall (declare block, etc)
if (!typeName.equals(BOOLEAN_STR) && !typeName.equals(XMLTYPE_STR)) {
typeName = typeName.concat(_TYPE_STR);
}
} else {
String oPLSQLTypeName = getOraclePLSQLTypeForName(typeName);
if (oPLSQLTypeName != null) {
typeName = oPLSQLTypeName;
}
}
return typeName;
}
/**
* Returns a list of ComplexTypeMetadata instances generated based on a list of
* CompositeDatabaseTypes. The given non-empty list should contain one or
* more of the following types:
* <ul>
* <li>PLSQLCollectionType
* <li>PLSQLRecordType
* <li>ObjectTableType
* <li>ObjectType
* <li>VArrayType
* </ul>
*/
protected static List<ComplexTypeMetadata> processCompositeTypes(List<CompositeDatabaseType> complexTypes, Project orProject) {
List<String> processedTypeNames = new ArrayList<String>();
List<ComplexTypeMetadata> processedTypes = new ArrayList<ComplexTypeMetadata>();
// process composite types
for (CompositeDatabaseType cdbType : complexTypes) {
ComplexTypeMetadata complexTypeMetadata = processDatabaseType(cdbType, orProject);
if (complexTypeMetadata != null) {
processedTypeNames.add(complexTypeMetadata.getName());
processedTypes.add(complexTypeMetadata);
}
}
// now handle processing composite enclosed types
for (CompositeDatabaseType cdbType : complexTypes) {
if (cdbType.getEnclosedType() != null && cdbType.getEnclosedType().isComposite()) {
CompositeDatabaseType enclosedType = (CompositeDatabaseType) cdbType.getEnclosedType();
ComplexTypeMetadata complexTypeMetadata = processDatabaseType(enclosedType, orProject, processedTypeNames);
if (complexTypeMetadata != null) {
processedTypeNames.add(complexTypeMetadata.getName());
processedTypes.add(complexTypeMetadata);
if (enclosedType.isObjectType()) {
for (FieldType ft : ((ObjectType) enclosedType).getFields()) {
if (ft.isComposite()) {
complexTypeMetadata = processDatabaseType(ft, orProject, processedTypeNames);
if (complexTypeMetadata != null) {
processedTypeNames.add(complexTypeMetadata.getName());
processedTypes.add(complexTypeMetadata);
}
}
}
} else if (enclosedType.isVArrayType()) {
VArrayType vType = (VArrayType) enclosedType;
if (vType.getEnclosedType().isComposite()) {
complexTypeMetadata = processDatabaseType((CompositeDatabaseType) vType.getEnclosedType(), orProject, processedTypeNames);
if (complexTypeMetadata != null) {
processedTypeNames.add(complexTypeMetadata.getName());
processedTypes.add(complexTypeMetadata);
}
}
}
}
}
}
return processedTypes;
}
/**
* Process the given CompositeDatabaseType and return a ComplexTypeMetadata
* instance. The given type is expected to be one of:
* <ul>
* <li>PLSQLCollectionType
* <li>PLSQLRecordType
* <li>ObjectTableType
* <li>ObjectType
* <li>VArrayType
* </ul>
* If the given type is not one of these, null is returned.
*/
protected static ComplexTypeMetadata processDatabaseType(CompositeDatabaseType cdbType, Project orProject) {
return processDatabaseType(cdbType, orProject, new ArrayList<String>());
}
/**
* Process the given CompositeDatabaseType and return a ComplexTypeMetadata
* instance. The given type is expected to be one of:
* <ul>
* <li>PLSQLCollectionType
* <li>PLSQLRecordType
* <li>ObjectTableType
* <li>ObjectType
* <li>VArrayType
* </ul>
* If the given type is not one of these, null is returned. Previously processed types
* are tracked to avoid unnecessary work.
*/
protected static ComplexTypeMetadata processDatabaseType(CompositeDatabaseType cdbType, Project orProject, List<String> processedTypeNames) {
if (!processedTypeNames.contains(cdbType.getTypeName())) {
if (cdbType.isPLSQLCollectionType()) {
return processPLSQLCollectionType((PLSQLCollectionType) cdbType);
}
if (cdbType.isPLSQLRecordType()) {
return processPLSQLRecordType((PLSQLRecordType) cdbType);
}
if (cdbType.isObjectTableType()) {
return processObjectTableType((ObjectTableType) cdbType, orProject);
}
if (cdbType.isObjectType()) {
return processObjectType((ObjectType) cdbType, orProject);
}
if (cdbType.isVArrayType()) {
return processVArrayType((VArrayType) cdbType, orProject);
}
}
return null;
}
/**
* Process the given PLSQLCollectionType and return a PLSQLTableMetadata instance.
*
*/
protected static ComplexTypeMetadata processPLSQLCollectionType(PLSQLCollectionType plsqlCollectionType) {
String typeName = plsqlCollectionType.getParentType().getPackageName() + DOT + plsqlCollectionType.getTypeName();
String compatiableName = plsqlCollectionType.getParentType().getPackageName() + UNDERSCORE + plsqlCollectionType.getTypeName();
PLSQLTableMetadata plsqlTable = new PLSQLTableMetadata();
plsqlTable.setName(typeName);
plsqlTable.setCompatibleType(compatiableName);
// handle Nested Table (i.e. non-Varray)
plsqlTable.setNestedTable(!plsqlCollectionType.isIndexed());
String dbType = plsqlCollectionType.getEnclosedType().getTypeName();
if (!(getJDBCTypeFromTypeName(dbType) == Types.OTHER)) {
// need special handling for nested PL/SQL scalar types
if (isArgPLSQLScalar(dbType)) {
plsqlTable.setNestedType(getOraclePLSQLTypeForName(dbType));
} else {
// OR Metadata doesn't handle VARCHAR2
if (dbType.equals(VARCHAR2_STR)) {
dbType = VARCHAR_STR;
}
plsqlTable.setNestedType(dbType + _TYPE_STR);
}
} else {
// may need to prepend package name
String pkg = null;
if (plsqlCollectionType.getEnclosedType() != null && plsqlCollectionType.getEnclosedType().isPLSQLType()) {
PLSQLType pType = (PLSQLType) plsqlCollectionType.getEnclosedType();
pkg = pType.getParentType().getPackageName();
}
plsqlTable.setNestedType(pkg == null ? dbType : pkg + DOT + dbType);
}
plsqlTable.setJavaType(typeName.toLowerCase() + COLLECTION_WRAPPER_SUFFIX);
return plsqlTable;
}
/**
* Process the given PLSQLRecordType and return a PLSQLRecordMetadata instance.
*
*/
protected static ComplexTypeMetadata processPLSQLRecordType(PLSQLRecordType plsqlRecordType) {
// for %ROWTYPE we create a 'place holder' PL/SQL Record - in this case there is no package name
String packageName = plsqlRecordType.getParentType().getPackageName();
String typeName = packageName != null ? plsqlRecordType.getParentType().getPackageName() + DOT + plsqlRecordType.getTypeName() : plsqlRecordType.getTypeName();
String compatiableName = packageName != null ? plsqlRecordType.getParentType().getPackageName() + UNDERSCORE + plsqlRecordType.getTypeName() : plsqlRecordType.getTypeName();
if (compatiableName.contains(PERCENT)) {
compatiableName = compatiableName.replace(PERCENT, UNDERSCORE);
}
PLSQLRecordMetadata plsqlRecordMetadata = new PLSQLRecordMetadata();
plsqlRecordMetadata.setName(typeName);
plsqlRecordMetadata.setCompatibleType(compatiableName);
if (typeName.endsWith(ROWTYPE_STR)) {
plsqlRecordMetadata.setJavaType(compatiableName.toLowerCase());
} else {
plsqlRecordMetadata.setJavaType(typeName.toLowerCase());
}
List<PLSQLParameterMetadata> fields = new ArrayList<PLSQLParameterMetadata>();
PLSQLParameterMetadata field;
for (FieldType fld : plsqlRecordType.getFields()) {
field = new PLSQLParameterMetadata();
field.setName(fld.getFieldName());
String pkg = null;
if (fld.getEnclosedType() != null && fld.getEnclosedType().isPLSQLType()) {
PLSQLType pType = (PLSQLType) fld.getEnclosedType();
pkg = pType.getParentType().getPackageName();
}
String dbType = fld.getTypeName();
if (!(getJDBCTypeFromTypeName(dbType) == Types.OTHER)) {
// OR Metadata doesn't handle VARCHAR2
if (dbType.equals(VARCHAR2_STR)) {
dbType = VARCHAR_STR;
}
if (!dbType.equals(BOOLEAN_STR)) {
dbType = dbType.concat(_TYPE_STR);
}
}
dbType = pkg == null ? dbType : pkg + DOT + dbType;
field.setDatabaseType(dbType);
fields.add(field);
}
plsqlRecordMetadata.setFields(fields);
return plsqlRecordMetadata;
}
/**
* Process the given ObjectTableType and return an OracleArrayTypeMetadata instance.
*
*/
protected static ComplexTypeMetadata processObjectTableType(ObjectTableType oTableType, Project orProject) {
ClassDescriptor cDesc = orProject.getDescriptorForAlias(getGeneratedAlias(oTableType.getTypeName()));
OracleArrayTypeMetadata oatMetadata = new OracleArrayTypeMetadata();
oatMetadata.setName(oTableType.getTypeName());
oatMetadata.setJavaType(cDesc.getJavaClassName());
oatMetadata.setNestedType(oTableType.getEnclosedType().getTypeName());
return oatMetadata;
}
/**
* Process the given ObjectType and return an OracleObjectTypeMetadata instance.
*
*/
protected static ComplexTypeMetadata processObjectType(ObjectType oType, Project orProject) {
ClassDescriptor cDesc = orProject.getDescriptorForAlias(getGeneratedAlias(oType.getTypeName()));
OracleObjectTypeMetadata ootMetadata = new OracleObjectTypeMetadata();
ootMetadata.setName(oType.getTypeName());
ootMetadata.setJavaType(cDesc.getJavaClassName());
List<PLSQLParameterMetadata> fields = new ArrayList<PLSQLParameterMetadata>();
for (FieldType ft : oType.getFields()) {
PLSQLParameterMetadata fieldMetadata = new PLSQLParameterMetadata();
fieldMetadata.setName(ft.getFieldName());
fieldMetadata.setDatabaseType(processTypeName(ft.getTypeName()));
fields.add(fieldMetadata);
}
ootMetadata.setFields(fields);
return ootMetadata;
}
/**
* Process the given VArrayType and return an OracleArrayTypeMetadata instance.
*
*/
protected static ComplexTypeMetadata processVArrayType(VArrayType vType, Project orProject) {
ClassDescriptor cDesc = orProject.getDescriptorForAlias(getGeneratedAlias(vType.getTypeName()));
OracleArrayTypeMetadata oatMetadata = new OracleArrayTypeMetadata();
oatMetadata.setName(vType.getTypeName());
oatMetadata.setJavaType(cDesc.getJavaClassName());
oatMetadata.setNestedType(processTypeName(vType.getEnclosedType().getTypeName()));
return oatMetadata;
}
/**
* Adds a ReturnNameValuePairsHint to the given query metadata instance.
*/
protected static void addQueryHint(NamedNativeQueryMetadata metadata) {
List<QueryHintMetadata> hints = metadata.getHints();
if (hints == null) {
hints = new ArrayList<QueryHintMetadata>();
}
QueryHintMetadata hint = new QueryHintMetadata();
hint.setName(QueryHints.RETURN_NAME_VALUE_PAIRS);
hint.setValue(HintValues.TRUE);
hints.add(hint);
metadata.setHints(hints);
}
}