/******************************************************************************* * 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.testing.tests.returning; import java.util.*; import org.eclipse.persistence.tools.schemaframework.*; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.queries.*; import org.eclipse.persistence.sessions.Project; import org.eclipse.persistence.internal.helper.DatabaseField; import org.eclipse.persistence.internal.helper.Helper; /** * This stored procedure generator is meant to generate INSERT and UPDATE * procedures that return values, but currently only generates * procedures that just perform the INSERT/UPDATE, so is not currently used. * It will hopefully be finished at some point... */ public class StoredProcedureGeneratorForAdapter extends StoredProcedureGenerator { public StoredProcedureGeneratorForAdapter(SchemaManager schemaMngr) { super(schemaMngr); insertStoredProcedures = new Hashtable(); updateStoredProcedures = new Hashtable(); substituteName = new Hashtable(); } protected Hashtable insertStoredProcedures; protected Hashtable updateStoredProcedures; protected Hashtable substituteName; protected boolean useTableNames; public boolean usesTableNames() { return useTableNames; } public void setUseTableNames(boolean useTableNames) { this.useTableNames = useTableNames; } /** * PUBLIC: * Inspired by StoredProcedureGenerator.generateStoredProcedures though * uses another attribute (insertStoredProcedures) and doesn't write definitions */ public void generateInsertStoredProceduresDefinitionsForProject(Project project) { verifyProject(project); Map descrpts = project.getDescriptors(); Iterator iterator = descrpts.keySet().iterator(); ClassDescriptor desc; while (iterator.hasNext()) { desc = (ClassDescriptor)descrpts.get(iterator.next()); if (desc.isDescriptorForInterface() || desc.isAggregateDescriptor()) { continue; } if (!desc.getQueryManager().hasInsertQuery()) { InsertObjectQuery insertQuery = new InsertObjectQuery(); insertQuery.setModifyRow(desc.getObjectBuilder().buildTemplateInsertRow(getSession())); desc.getQueryManager().setInsertQuery(insertQuery); } StoredProcedureDefinition definition = generateStoredProcedureDefinition(desc, desc.getQueryManager().getInsertQuery(), "INS_"); insertStoredProcedures.put(desc, definition); } } public void generateUpdateStoredProceduresDefinitionsForProject(Project project) { verifyProject(project); Map descrpts = project.getDescriptors(); Iterator iterator = descrpts.keySet().iterator(); ClassDescriptor desc; while (iterator.hasNext()) { desc = (ClassDescriptor)descrpts.get(iterator.next()); if (desc.isDescriptorForInterface() || desc.isAggregateDescriptor()) { continue; } if (!desc.getQueryManager().hasUpdateQuery()) { UpdateObjectQuery updateQuery = new UpdateObjectQuery(); updateQuery.setModifyRow(desc.getObjectBuilder().buildTemplateUpdateRow(getSession())); if (updateQuery.getModifyRow().size() > 0) { desc.getQueryManager().setUpdateQuery(updateQuery); } } if (desc.getQueryManager().getUpdateQuery() != null) { StoredProcedureDefinition definition = generateStoredProcedureDefinition(desc, desc.getQueryManager().getUpdateQuery(), "UPD_"); updateStoredProcedures.put(desc, definition); } } } protected StoredProcedureDefinition generateStoredProcedureDefinition(ClassDescriptor desc, DatabaseQuery query, String namePrefix) { Vector fields = desc.getFields(); Hashtable namesNewToNames = null; if (shouldCapitalizeNames()) { namesNewToNames = new Hashtable(); fields = capitalize(fields, namesNewToNames); } StoredProcedureDefinition definition = generateObjectStoredProcedure(query, fields, namePrefix); if (namesNewToNames != null && !namesNewToNames.isEmpty()) { substituteName.put(definition, namesNewToNames); } return definition; } public void generateStoredProceduresDefinitionsForProject(Project project) { generateInsertStoredProceduresDefinitionsForProject(project); generateUpdateStoredProceduresDefinitionsForProject(project); } /** * PUBLIC: */ public void writeInsertStoredProcedures() { Enumeration descriptorEnum = insertStoredProcedures.keys(); while (descriptorEnum.hasMoreElements()) { ClassDescriptor descriptor = (ClassDescriptor)descriptorEnum.nextElement(); StoredProcedureDefinition definition = (StoredProcedureDefinition)insertStoredProcedures.get(descriptor); writeDefinition(definition); } } public void writeUpdateStoredProcedures() { Enumeration descriptorEnum = updateStoredProcedures.keys(); while (descriptorEnum.hasMoreElements()) { ClassDescriptor descriptor = (ClassDescriptor)descriptorEnum.nextElement(); StoredProcedureDefinition definition = (StoredProcedureDefinition)updateStoredProcedures.get(descriptor); writeDefinition(definition); } } public void writeStoredProcedures() { writeInsertStoredProcedures(); writeUpdateStoredProcedures(); } /** * INTERNAL: * The base class doesn't allow optimistic locking in getSession().getProject() - * override this restriction. */ protected void verify() throws org.eclipse.persistence.exceptions.ValidationException { } /** * INTERNAL: * The base class doesn't allow optimistic locking in the project. */ protected void verifyProject(Project project) { if (project.usesOptimisticLocking()) { throw org.eclipse.persistence.exceptions.ValidationException.optimisticLockingNotSupportedWithStoredProcedureGeneration(); } } /** * PUBLIC: * Amends descriptors with stored procedures */ public void amendDescriptorsInsertQuery() { Enumeration descriptorEnum = insertStoredProcedures.keys(); while (descriptorEnum.hasMoreElements()) { ClassDescriptor descriptor = (ClassDescriptor)descriptorEnum.nextElement(); StoredProcedureDefinition definition = (StoredProcedureDefinition)insertStoredProcedures.get(descriptor); InsertObjectQuery insertQuery = new InsertObjectQuery(); defineQuery(insertQuery, definition); descriptor.getQueryManager().setInsertQuery(insertQuery); } } public void amendDescriptorsUpdateQuery() { Enumeration descriptorEnum = updateStoredProcedures.keys(); while (descriptorEnum.hasMoreElements()) { ClassDescriptor descriptor = (ClassDescriptor)descriptorEnum.nextElement(); StoredProcedureDefinition definition = (StoredProcedureDefinition)updateStoredProcedures.get(descriptor); UpdateObjectQuery updateQuery = new UpdateObjectQuery(); descriptor.getQueryManager().setUpdateQuery(updateQuery); } } public void defineQuery(DatabaseQuery query, StoredProcedureDefinition definition) { Hashtable namesNewToNames = (Hashtable)substituteName.get(definition); query.setShouldBindAllParameters(true); StoredProcedureCall call = new StoredProcedureCall(); call.setProcedureName(definition.getName()); for (int i = 0; i < definition.getArguments().size(); i++) { FieldDefinition fieldDefinition = ((FieldDefinition)definition.getArguments().elementAt(i)); String procedureParameterName = fieldDefinition.getName(); String fieldName = getFieldName(fieldDefinition.getName()); String argumentFieldName = fieldName; if (namesNewToNames != null) { String fieldNameOriginal = (String)namesNewToNames.get(fieldName); if (fieldNameOriginal != null) { argumentFieldName = fieldNameOriginal; } } call.addNamedArgument(procedureParameterName, argumentFieldName); } query.setCall(call); } public void amendDescriptors() { amendDescriptorsInsertQuery(); amendDescriptorsUpdateQuery(); } // Need for capitalization is caused by bug3172139: // ORACLE CONNECTION METADATA.GETCOLUMNS FAILS IF PASSED LOWER-CASE NAMES // In case the bug is fixed, there would be no need for returning newFields. // However namesCapitalizedToNames still will be needed, because the DatabaseField's // name to be used as a parameter for StoredProcedureCall is extracted from // storedProcedureDefinition - and there it is always the same as in database. protected Vector capitalize(Vector fields, Hashtable namesCapitalizedToNames) { // Can't change names of descriptor's fields, create a new Vector. Vector newFields = null; for (int i = 0; i < fields.size(); i++) { DatabaseField field = (DatabaseField)fields.elementAt(i); String fieldNameUpper = field.getName().toUpperCase(); String tableNameUpper = field.getTableName().toUpperCase(); if (!fieldNameUpper.equals(field.getName()) || !tableNameUpper.equals(field.getTableName())) { DatabaseField newField = new DatabaseField(fieldNameUpper, tableNameUpper); newField.setType(field.getType()); if (newFields == null) { newFields = (Vector)fields.clone(); } newFields.set(i, newField); namesCapitalizedToNames.put(fieldNameUpper, field.getName()); } } if (newFields == null) { return fields; } else { return newFields; } } protected boolean shouldCapitalizeNames() { return getSession().getPlatform().isOracle(); } protected String shortClassName(String originalClassName, int numberOfPackagesToIncludeIntoShortName) { int nLastIndex = originalClassName.length() - 1; for (int i = 0; i <= numberOfPackagesToIncludeIntoShortName && nLastIndex > 0; i++) { nLastIndex = originalClassName.lastIndexOf('.', nLastIndex - 1); } if (nLastIndex < 0 || nLastIndex == originalClassName.length() - 1) { return new String(originalClassName); } else { return originalClassName.substring(nLastIndex + 1); } } protected StoredProcedureDefinition generateObjectStoredProcedure(DatabaseQuery query, Vector fields, String namePrefix) { String namePrefixToUse = namePrefix; String className = Helper.getShortClassName(query.getDescriptor().getJavaClass()); if (useTableNames) { String tableName = query.getDescriptor().getTableName(); if (!compareNames(className, tableName)) { namePrefixToUse = namePrefix + tableName + "_"; } } return generateStoredProcedure(query, fields, getPrefix() + namePrefixToUse + className); } protected boolean compareNames(String name1, String name2) { if (shouldCapitalizeNames()) { return name1.equalsIgnoreCase(name2); } else { return name1.equals(name2); } } }