blob: e2b40378c7a06b3815e2fdf40aa2441dbda5ecfb [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
// 09/09/2011-2.3.1 Guy Pelletier
// - 356197: Add new VPD type to MultitenantType
// 09/14/2011-2.3.1 Guy Pelletier
// - 357533: Allow DDL queries to execute even when Multitenant entities are part of the PU
// 02/04/2013-2.5 Guy Pelletier
// - 389090: JPA 2.1 DDL Generation Support
package org.eclipse.persistence.tools.schemaframework;
import java.io.*;
import java.util.Map;
import java.util.Set;
import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform;
import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.exceptions.*;
import org.eclipse.persistence.queries.*;
/**
* <p>
* <b>Purpose</b>: Define a database object for the purpose of creation and deletion.
* A database object is an entity such as a table, view, proc, sequence...
* <p>
* <b>Responsibilities</b>:
* <ul>
* <li> Be able to create and drop the object from the database.
* </ul>
*/
public abstract class DatabaseObjectDefinition implements Cloneable, Serializable {
public String name;
public String qualifier;
/**
* INTERNAL:
* Retrieve a database platform specific definition from session for
* existing type instance or build a new one when type is {@code null}.
* @param session Session to search for already existing instances.
* @param type Field type class.
* @param name Filed type name.
* @return Database platform specific definition instance.
* @throws ValidationException when provided type is not valid database type.
*/
protected static final FieldTypeDefinition getFieldTypeDefinition(
final AbstractSession session, final Class type, final String name) {
final FieldTypeDefinition fieldType = type != null
? session.getPlatform().getFieldTypeDefinition(type)
: new FieldTypeDefinition(name);
if (fieldType == null) {
throw ValidationException.javaTypeIsNotAValidDatabaseType(type);
}
return fieldType;
}
/**
* INTERNAL:
* Retrieve database platform specific field definition from database
* specific platform handler for existing type or build a new one when type
* is {@code null} and type for type name could not be found.
* @param platform Specific database platform handler.
* @param type Field type (will be processed first when available).
* @param name Field type name (will be processed as backup option when
* type class is not available).
* @throws ValidationException when provided type is not valid database type.
*/
protected static final FieldTypeDefinition getFieldTypeDefinition(
final DatabasePlatform platform, final Class type, final String name) {
FieldTypeDefinition fieldType;
if (type != null) { //translate Java 'type'
fieldType = platform.getFieldTypeDefinition(type);
if (fieldType == null) {
throw ValidationException.javaTypeIsNotAValidDatabaseType(type);
}
} else if (name != null) { //translate generic type name
final Map<String, Class> fieldTypes = platform.getClassTypes();
final Class typeFromName = fieldTypes.get(name);
if (typeFromName == null) { // if unknown type name, use as it is
fieldType = new FieldTypeDefinition(name);
} else {
fieldType = platform.getFieldTypeDefinition(typeFromName);
if (fieldType == null) {
throw ValidationException.javaTypeIsNotAValidDatabaseType(typeFromName);
}
}
} else {
// Both type and typeName is null
throw ValidationException.javaTypeIsNotAValidDatabaseType(null);
}
return fieldType;
}
protected DatabaseObjectDefinition() {
this.name = "";
this.qualifier = "";
}
/**
* INTERNAL:
* Returns the writer used for creation of this object.
*/
public abstract Writer buildCreationWriter(AbstractSession session, Writer writer) throws ValidationException;
/**
* INTERNAL:
* Sub classes should override.
*/
public Writer buildVPDCreationPolicyWriter(AbstractSession session, Writer writer) {
// Does nothing .. subclasses should override
return null;
}
/**
* INTERNAL:
* Sub classes should override.
*/
public Writer buildVPDCreationFunctionWriter(AbstractSession session, Writer writer) {
// Does nothing .. subclasses should override
return null;
}
/**
* INTERNAL:
* Sub classes should override.
*/
public Writer buildVPDDeletionWriter(AbstractSession session, Writer writer) {
// Does nothing .. subclasses should override
return null;
}
/**
* INTERNAL:
* Returns the writer used for deletion of this object.
*/
public abstract Writer buildDeletionWriter(AbstractSession session, Writer writer) throws ValidationException;
/**
* PUBLIC:
*/
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException impossible) {
return null;
}
}
/**
* INTERNAL:
* Execute the DDL to create the database schema for this object.
* Does nothing at this level, subclasses that support this must override
* this method.
*
* @see TableDefinition
*/
public void createDatabaseSchema(AbstractSession session, Writer writer, Set<String> createdDatabaseSchemas) throws EclipseLinkException {}
/**
* INTERNAL:
* Execute the DDL to create the database schema for this object.
* Does nothing at this level, subclasses that support this must override
* this method.
*
* @see TableDefinition
*/
public void createDatabaseSchemaOnDatabase(AbstractSession session, Set<String> createdDatabaseSchemas) throws EclipseLinkException {}
/**
* INTERNAL:
* Either drop from the database directly or write the statement to a file.
* Database objects are root level entities such as tables, views, procs, sequences...
*/
public void createObject(AbstractSession session, Writer schemaWriter) throws EclipseLinkException {
if (schemaWriter == null) {
this.createOnDatabase(session);
} else {
this.buildCreationWriter(session, schemaWriter);
if (shouldCreateVPDCalls(session)) {
buildVPDCreationPolicyWriter(session, schemaWriter);
buildVPDCreationFunctionWriter(session, schemaWriter);
}
}
}
/**
* INTERNAL:
* Execute the DDL to create this object.
*/
public void createOnDatabase(AbstractSession session) throws EclipseLinkException {
session.priviledgedExecuteNonSelectingCall(new SQLCall(buildCreationWriter(session, new StringWriter()).toString()));
if (shouldCreateVPDCalls(session)) {
session.priviledgedExecuteNonSelectingCall(new SQLCall(buildVPDCreationPolicyWriter(session, new StringWriter()).toString()));
session.priviledgedExecuteNonSelectingCall(new SQLCall(buildVPDCreationFunctionWriter(session, new StringWriter()).toString()));
}
}
/**
* INTERNAL:
* Subclasses who care should override this method, e.g. TableDefinition.
*/
public boolean shouldCreateDatabaseSchema(Set<String> createdDatabaseSchemas) {
return false;
}
/**
* INTERNAL:
* Subclasses who care should override this method.
*/
public boolean shouldCreateVPDCalls(AbstractSession session) {
return false;
}
/**
* INTERNAL:
* Execute the DDL to drop the database schema for this object.
* Does nothing at this level, subclasses that support this must override
* this method.
*
* @see TableDefinition
*/
public void dropDatabaseSchema(AbstractSession session, Writer writer) throws EclipseLinkException {}
/**
* INTERNAL:
* Execute the DDL to drop the database schema for this object.
* Does nothing at this level, subclasses that support this must override
* this method.
*
* @see TableDefinition
*/
public void dropDatabaseSchemaOnDatabase(AbstractSession session) throws EclipseLinkException {}
/**
* INTERNAL:
* Execute the DDL to drop the object.
*/
public void dropFromDatabase(AbstractSession session) throws EclipseLinkException {
session.priviledgedExecuteNonSelectingCall(new SQLCall(buildDeletionWriter(session, new StringWriter()).toString()));
if (shouldCreateVPDCalls(session)) {
session.priviledgedExecuteNonSelectingCall(new SQLCall(buildVPDDeletionWriter(session, new StringWriter()).toString()));
}
}
/**
* INTERNAL:
* Execute the DDL to drop the object. Either directly from the database
* of write out the statement to a file.
*/
public void dropObject(AbstractSession session, Writer schemaWriter, boolean createSQLFiles) throws EclipseLinkException {
if (schemaWriter == null) {
this.dropFromDatabase(session);
} else {
buildDeletionWriter(session, schemaWriter);
if (shouldCreateVPDCalls(session)) {
buildVPDDeletionWriter(session, schemaWriter);
}
}
}
/**
* PUBLIC:
* Return the database schema associated with this database object.
*
* @see TableDefinition
*/
public String getDatabaseSchema() {
return null;
}
/**
* INTERNAL:
* Most major databases support a creator name scope.
* This means whenever the database object is referenced, it must be qualified.
*/
public String getFullName() {
if (getQualifier().equals("")) {
return getName();
} else {
return getQualifier() + "." + getName();
}
}
/**
* PUBLIC:
* Return the name of the object.
* i.e. the table name or the sequence name.
*/
public String getName() {
return name;
}
/**
* PUBLIC:
* Most major databases support a creator name scope.
* This means whenever the database object is referenced, it must be qualified.
*/
public String getQualifier() {
return qualifier;
}
/**
* INTERNAL:
* Return true is this database object definition has a schema definition.
*/
protected boolean hasDatabaseSchema() {
return getDatabaseSchema() != null && ! getDatabaseSchema().equals("");
}
/**
* Execute any statements required after the creation of the object
*/
public void postCreateObject(AbstractSession session, Writer createSchemaWriter, boolean createSQLFiles){
}
/**
* Execute any statements required before the deletion of the object
*/
public void preDropObject(AbstractSession session, Writer dropSchemaWriter, boolean createSQLFiles){
}
/**
* PUBLIC:
* Set the name of the object.
* i.e. the table name or the sequence name.
*/
public void setName(String name) {
this.name = name;
}
/**
* PUBLIC:
* Most major databases support a creator name scope.
* This means whenever the database object is referenced, it must be qualified.
*/
public void setQualifier(String qualifier) {
this.qualifier = qualifier;
}
@Override
public String toString() {
return Helper.getShortClassName(getClass()) + "(" + getFullName() + ")";
}
}