/******************************************************************************* * Copyright (c) 1998, 2016 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: * 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); } }