/******************************************************************************* | |
* 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.tools.workbench.platformsmodel; | |
import java.util.Iterator; | |
import java.util.List; | |
import org.eclipse.persistence.tools.workbench.utility.ClassTools; | |
import org.eclipse.persistence.tools.workbench.utility.XMLTools; | |
import org.eclipse.persistence.tools.workbench.utility.node.AbstractNodeModel; | |
import org.w3c.dom.Node; | |
/** | |
* A database type holds all the settings for a platform-specific database type. | |
* For example, the Oracle database type VARCHAR2 | |
* - maps to the JDBC type VARCHAR | |
* - allows and requires a size specification | |
* - has a initial size of 20 when generating tables | |
* - does not allow a sub-size specification | |
* - allows a null value | |
*/ | |
public final class DatabaseType | |
extends AbstractNodeModel | |
{ | |
/** | |
* a name uniquely identifying the type within a | |
* database platform | |
*/ | |
private String name; | |
public static final String NAME_PROPERTY = "name"; | |
/** | |
* the JDBC type most closely resembling the | |
* platform-specific database type | |
*/ | |
private JDBCType jdbcType; | |
public static final String JDBC_TYPE_PROPERTY = "jdbcType"; | |
/** | |
* whether the type can be declared with a size | |
*/ | |
private boolean allowsSize; | |
public static final String ALLOWS_SIZE_PROPERTY = "allowsSize"; | |
/** | |
* whether the type *requires* a size... | |
*/ | |
private boolean requiresSize; | |
public static final String REQUIRES_SIZE_PROPERTY = "requiresSize"; | |
/** | |
* ...and, if it does, what the initial size should be | |
*/ | |
private int initialSize; | |
public static final String INITIAL_SIZE_PROPERTY = "initialSize"; | |
/** | |
* whether the type can be declared with a "sub-size"; | |
* this is typically a numeric scale | |
*/ | |
private boolean allowsSubSize; | |
public static final String ALLOWS_SUB_SIZE_PROPERTY = "allowsSubSize"; | |
/** | |
* whether the type allows NULL values | |
*/ | |
private boolean allowsNull; | |
public static final String ALLOWS_NULL_PROPERTY = "allowsNull"; | |
// ********** constructors ********** | |
/** | |
* this constructor is called when the type is read from an XML file | |
*/ | |
DatabaseType(DatabasePlatform platform, Node node) throws CorruptXMLException { | |
super(platform); | |
this.read(node); | |
} | |
/** | |
* this constructor is called when the user (or a test case) | |
* creates a new type (which shouldn't happen very often, | |
* since all the typical platforms have already been built...) | |
*/ | |
DatabaseType(DatabasePlatform platform, String name) { | |
super(platform); | |
this.name = name; | |
this.jdbcType = this.jdbcTypeRepository().getDefaultJDBCType(); | |
} | |
// ********** initialization ********** | |
/** | |
* @see org.eclipse.persistence.tools.workbench.utility.AbstractNodeModel#initialize() | |
*/ | |
protected void initialize() { | |
super.initialize(); | |
this.allowsSize = true; | |
this.requiresSize = false; | |
this.initialSize = 0; | |
this.allowsSubSize = false; | |
this.allowsNull = true; | |
} | |
// ********** accessors ********** | |
public DatabasePlatform getPlatform() { | |
return (DatabasePlatform) this.getParent(); | |
} | |
public String getName() { | |
return this.name; | |
} | |
public void setName(String name) { | |
this.getPlatform().checkDatabaseTypeName(name); | |
Object old = this.name; | |
this.name = name; | |
this.firePropertyChanged(NAME_PROPERTY, old, name); | |
} | |
public JDBCType getJDBCType() { | |
return this.jdbcType; | |
} | |
public void setJDBCType(JDBCType jdbcType) { | |
if (jdbcType == null) { | |
throw new NullPointerException(); | |
} | |
Object old = this.jdbcType; | |
this.jdbcType = jdbcType; | |
this.firePropertyChanged(JDBC_TYPE_PROPERTY, old, jdbcType); | |
} | |
public boolean allowsSize() { | |
return this.allowsSize; | |
} | |
public void setAllowsSize(boolean allowsSize) { | |
boolean old = this.allowsSize; | |
this.allowsSize = allowsSize; | |
this.firePropertyChanged(ALLOWS_SIZE_PROPERTY, old, allowsSize); | |
// if size is not allowed, sub-size is not either and size cannot be required | |
if ( ! allowsSize) { | |
this.setAllowsSubSize(false); | |
this.setRequiresSize(false); | |
} | |
} | |
public boolean requiresSize() { | |
return this.requiresSize; | |
} | |
public void setRequiresSize(boolean requiresSize) { | |
boolean old = this.requiresSize; | |
this.requiresSize = requiresSize; | |
this.firePropertyChanged(REQUIRES_SIZE_PROPERTY, old, requiresSize); | |
// if size is required, size must be allowed... | |
if (requiresSize) { | |
this.setAllowsSize(true); | |
} else { | |
this.setInitialSize(0); | |
} | |
} | |
public int getInitialSize() { | |
return this.initialSize; | |
} | |
public void setInitialSize(int initialSize) { | |
if (initialSize < 0) { | |
throw new IllegalArgumentException("initial size must be greater than or equal to zero" + initialSize); | |
} | |
int old = this.initialSize; | |
this.initialSize = initialSize; | |
this.firePropertyChanged(INITIAL_SIZE_PROPERTY, old, initialSize); | |
// if there is a initial size, it must be required | |
if (initialSize != 0) { | |
this.setRequiresSize(true); | |
} | |
} | |
public boolean allowsSubSize() { | |
return this.allowsSubSize; | |
} | |
public void setAllowsSubSize(boolean allowsSubSize) { | |
boolean old = this.allowsSubSize; | |
this.allowsSubSize = allowsSubSize; | |
this.firePropertyChanged(ALLOWS_SUB_SIZE_PROPERTY, old, allowsSubSize); | |
// if sub-size is allowed, size must be also | |
if (allowsSubSize) { | |
this.setAllowsSize(true); | |
} | |
} | |
public boolean allowsNull() { | |
return this.allowsNull; | |
} | |
public void setAllowsNull(boolean allowsNull) { | |
boolean old = this.allowsNull; | |
this.allowsNull = allowsNull; | |
this.firePropertyChanged(ALLOWS_NULL_PROPERTY, old, allowsNull); | |
} | |
// ********** queries ********** | |
/** | |
* return a Java type declaration that can used for this database type; | |
* this is used for generating classes from tables | |
*/ | |
public JavaTypeDeclaration javaTypeDeclaration() { | |
return this.jdbcTypeRepository().javaTypeDeclarationFor(this.getJDBCType()); | |
} | |
private DatabasePlatformRepository platformRepository() { | |
return this.getPlatform().getRepository(); | |
} | |
private JDBCTypeRepository jdbcTypeRepository() { | |
return this.platformRepository().getJDBCTypeRepository(); | |
} | |
private JDBCType jdbcTypeNamed(String jdbcTypeName) { | |
return this.jdbcTypeRepository().jdbcTypeNamed(jdbcTypeName); | |
} | |
/** | |
* Return all the JDBC types that the database type | |
* could be mapped to. Simplifies UI code.... | |
*/ | |
public Iterator jdbcTypes() { | |
return this.jdbcTypeRepository().jdbcTypes(); | |
} | |
/** | |
* Return the size of all the JDBC types that the database type | |
* could be mapped to. Simplifies UI code.... | |
*/ | |
public int jdbcTypesSize() { | |
return this.jdbcTypeRepository().jdbcTypesSize(); | |
} | |
// ********** behavior ********** | |
protected void addProblemsTo(List currentProblems) { | |
if (this.requiresSize() && (this.getInitialSize() == 0)) { | |
currentProblems.add(this.buildProblem("003", this.getPlatform().getName(), this.getName())); | |
} | |
super.addProblemsTo(currentProblems); | |
} | |
/** | |
* @see org.eclipse.persistence.tools.workbench.utility.AbstractNodeModel#nodeRemoved(org.eclipse.persistence.tools.workbench.utility.Node) | |
*/ | |
public void nodeRemoved(org.eclipse.persistence.tools.workbench.utility.node.Node node) { | |
super.nodeRemoved(node); | |
if (this.jdbcType == node) { | |
this.setJDBCType(this.jdbcTypeRepository().getDefaultJDBCType()); | |
} | |
} | |
/** | |
* copy all the settings from the original type | |
* to this, newly-created, type | |
*/ | |
void cloneFrom(DatabaseType originalType) { | |
// the name has been set by the time we get here | |
this.setComment(originalType.getComment()); | |
this.setJDBCType(originalType.getJDBCType()); // the JDBC type should NOT be cloned | |
this.setAllowsSize(originalType.allowsSize()); | |
this.setRequiresSize(originalType.requiresSize()); | |
this.setInitialSize(originalType.getInitialSize()); | |
this.setAllowsSubSize(originalType.allowsSubSize()); | |
this.setAllowsNull(originalType.allowsNull()); | |
} | |
// ********** i/o ********** | |
private void read(Node node) throws CorruptXMLException { | |
if (node == null) { | |
throw this.buildCorruptXMLException("missing node"); | |
} | |
this.name = XMLTools.childTextContent(node, "name", null); | |
if ((this.name == null) || (this.name.length() == 0)) { | |
throw this.buildCorruptXMLException("name is required"); | |
} | |
ClassTools.setFieldValue(this, "comment", XMLTools.childTextContent(node, "comment", "")); | |
String jdbcTypeName = XMLTools.childTextContent(node, "jdbc-type", null); | |
try { | |
this.jdbcType = this.jdbcTypeNamed(jdbcTypeName); | |
} catch (IllegalArgumentException ex) { | |
throw this.buildCorruptXMLException(ex); | |
} | |
this.allowsSize = XMLTools.childBooleanContent(node, "allows-size", false); | |
this.requiresSize = XMLTools.childBooleanContent(node, "requires-size", false); | |
if (( ! this.allowsSize) && this.requiresSize) { | |
throw this.buildCorruptXMLException("size cannot be required when it is not allowed"); | |
} | |
this.initialSize = XMLTools.childIntContent(node, "initial-size", 0); | |
if (( ! this.requiresSize) && (this.initialSize != 0)) { | |
throw this.buildCorruptXMLException("initial size cannot be specified when size is not required"); | |
} | |
this.allowsSubSize = XMLTools.childBooleanContent(node, "allows-sub-size", false); | |
if (( ! this.allowsSize) && this.allowsSubSize) { | |
throw this.buildCorruptXMLException("sub-size cannot be allowed when size is not allowed"); | |
} | |
this.allowsNull = XMLTools.childBooleanContent(node, "allows-null", false); | |
} | |
/** | |
* tack on some more information on the message | |
*/ | |
private CorruptXMLException buildCorruptXMLException(String message) { | |
return new CorruptXMLException(message + " (" + this.corruptXMLLocation() + ")"); | |
} | |
/** | |
* tack on some more information on the message | |
*/ | |
private CorruptXMLException buildCorruptXMLException(Throwable t) { | |
return new CorruptXMLException(this.corruptXMLLocation(), t); | |
} | |
private String corruptXMLLocation() { | |
return this.getPlatform().getName() + ":" + this.name; | |
} | |
void write(Node node) { | |
XMLTools.addSimpleTextNode(node, "name", this.name); | |
XMLTools.addSimpleTextNode(node, "comment", (String) ClassTools.getFieldValue(this, "comment"), ""); | |
XMLTools.addSimpleTextNode(node, "jdbc-type", this.jdbcType.getName()); | |
XMLTools.addSimpleTextNode(node, "allows-size", this.allowsSize, false); | |
XMLTools.addSimpleTextNode(node, "requires-size", this.requiresSize, false); | |
XMLTools.addSimpleTextNode(node, "initial-size", this.initialSize, 0); | |
XMLTools.addSimpleTextNode(node, "allows-sub-size", this.allowsSubSize, false); | |
XMLTools.addSimpleTextNode(node, "allows-null", this.allowsNull, false); | |
} | |
// ********** printing and displaying ********** | |
/** | |
* @see org.eclipse.persistence.tools.workbench.utility.Node#displayString() | |
*/ | |
public String displayString() { | |
return this.name; | |
} | |
/** | |
* @see org.eclipse.persistence.tools.workbench.utility.AbstractModel#toString(StringBuffer) | |
*/ | |
public void toString(StringBuffer sb) { | |
sb.append(this.name); | |
} | |
} |