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