blob: 88d77fa0105b5b0e54982ca3d51adb1cd47b12a0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.dbschema;
import java.io.*;
import java.text.MessageFormat;
import java.util.*;
import org.netbeans.modules.dbschema.util.*;
import org.netbeans.modules.dbschema.migration.archiver.*;
import org.openide.nodes.Node;
/** Describes an entire database schema.
*/
public class SchemaElement extends DBElement implements Node.Cookie {
/** Status when the schema element is not yet prepared. */
public static final int STATUS_NOT = 0;
/** Status when the schema element contains unrecoverable errors. */
public static final int STATUS_ERROR = 1;
/** Status when the schema element contains minor errors. */
public static final int STATUS_PARTIAL = 2;
/** Status when the schema element has been parsed and is error-free. */
public static final int STATUS_OK = 3;
/** Version of the database schema API. */
public static final int CURRENT_VERSION_NO = 2;
private int versionNo;
/** Creates a new schema element represented in memory.
*/
public SchemaElement() {
this(new Memory());
}
/** Creates a new schema element.
* @param impl the pluggable implementation
*/
public SchemaElement(Impl impl) {
super(impl);
}
/** Returns the implementation for the schema.
* @return implementation for the schema
*/
final Impl getSchemaImpl() {
return (Impl)getElementImpl();
}
/** Returns if the schema is compatible with current API version.
* @return true if schema is compatible; false otherwise
*/
public boolean isCompatibleVersion() {
return (getVersionNo() == CURRENT_VERSION_NO);
}
/** Getter for property versionNo.
* @return Value of property versionNo.
*/
public int getVersionNo() {
return versionNo;
}
/** Setter for property versionNo.
* @param versionNo New value of property versionNo.
*/
public void setVersionNo(int versionNo) {
this.versionNo = versionNo;
}
/** Cache for read schemas. */
protected static Map schemaCache = new HashMap();
/** Last used schema. */
private static SchemaElement lastSchema;
/** Returns the last used schema.
* @return the last used schema
*/
protected static SchemaElement getLastSchema() {
return lastSchema;
}
/** Sets the last used schema.
* @param last the last used schema
*/
protected static void setLastSchema(SchemaElement last) {
lastSchema = last;
}
/** Removes the specified schema from cache.
* @param name the schema to remove
*/
public static void removeFromCache(String name) {
synchronized (schemaCache) {
if (getLastSchema() != null)
if (getLastSchema().getName().getFullName().equals(name))
setLastSchema(null);
schemaCache.remove(name);
}
}
/** Adds the specified schema element to cache.
* @param schema the schema element to add
*/
public static void addToCache(SchemaElement schema) {
synchronized (schemaCache) {
schemaCache.put(schema.getName().getFullName(), schema);
SchemaElement.setLastSchema(schema);
}
}
/** Returns the SchemaElement object associated with the schema with
* the given string name and object. The second argument is meant to
* help define the context for loading of the schema and can be a
* FileObject[] or FileObject for use in the IDE or a ClassLoader for
* use at runtime. Note that if if FileObject[] is used, the first match
* is returned if it's not already in the cache. It might be extended
* later to accept a Project as well. Any other non-null value for the
* second argument will result in an UnsupportedOperationException.
* @param name the schema name
* @param obj the schema context
* @return the SchemaElement object for the given schema name
*/
public static SchemaElement forName(String name, Object obj) {
if (IDEUtil.isIDERunning())
return SchemaElementUtil.forName(name, obj);
if (obj == null)
return forNameInternal(name, SchemaElement.class.getClassLoader());
if (obj instanceof ClassLoader)
return forNameInternal(name, (ClassLoader)obj);
// if we got to this point the second object is not null, the
// IDE is not running, and the type of object is not one we can
// handle
throw new UnsupportedOperationException("Cannot lookup schema " +
name + " in context of type " + obj.getClass() +
" expected ClassLoader or null.");
}
/** Returns the SchemaElement object associated with the schema with the given string name, loaded by the given classloader.
* @param name the schema name
* @param cl the schema classloader
* @return the SchemaElement object for the given schema name
*/
private static SchemaElement forNameInternal(String name, ClassLoader cl) {
SchemaElement se = getLastSchema();
if (se != null && se.getName().getFullName().equals(name))
return se;
else
synchronized (schemaCache) {
se = (SchemaElement) schemaCache.get(name);
if (se != null)
return se;
InputStream is = cl.getResourceAsStream(NameUtil.getSchemaResourceName(name));
if (is != null)
try {
ObjectInput i = new XMLInputStream(is);
se = (SchemaElement) i.readObject();
if (!se.isCompatibleVersion()) {
String message = MessageFormat.format(ResourceBundle.getBundle("org.netbeans.modules.dbschema.resources.Bundle").getString("PreviousVersion"), new String[] {name}); //NOI18N
System.out.println(message);
}
i.close();
se.setName(DBIdentifier.create(name));
SchemaElement.addToCache(se);
// MBO: now set the declaring schema in TableElement(transient field)
TableElement tables[] = se.getTables();
int size = (tables != null) ? tables.length : 0;
for (int j = 0; j < size; j++)
tables[j].setDeclaringSchema(se);
} catch (Exception exc) {
if (Boolean.getBoolean("netbeans.debug.exceptions")) // NOI18N
System.out.println(ResourceBundle.getBundle("org.netbeans.modules.dbschema.resources.Bundle").getString("SchemaNotFound")); //NOI18N
}
else
if (Boolean.getBoolean("netbeans.debug.exceptions")) // NOI18N
System.out.println(ResourceBundle.getBundle("org.netbeans.modules.dbschema.resources.Bundle").getString("SchemaNotFound")); //NOI18N
return se;
}
}
/** Returns the SchemaElement object associated with the schema with the given string name.
* @param name the schema name
* @return the SchemaElement object for the given schema name
*/
public static SchemaElement forName(String name) {
return forName(name, null);
}
/** Gets the parsing status of the element.
* This is a non-blocking operation.
* @return one of {@link #STATUS_NOT}, {@link #STATUS_ERROR}, {@link
* #STATUS_PARTIAL}, or {@link #STATUS_OK}
*/
public int getStatus() {
return getSchemaImpl().getStatus();
}
/** Sets the schema name of this schema snapshot.
* @param id the schema name, or <code>null</code>
* @exception DBException if the operation cannot proceed
*/
public void setSchema(DBIdentifier schema) throws DBException {
getSchemaImpl().setSchema(schema);
}
/** Gets the schema name of this schema snapshot.
* @return the schema name, or <code>null</code> if this snapshot does not
* have a schema name
*/
public DBIdentifier getSchema() {
return getSchemaImpl().getSchema();
}
/** Sets the catalog name of this schema snapshot.
* @param id the catalog name, or <code>null</code>
* @exception DBException if the operation cannot proceed
*/
public void setCatalog(DBIdentifier catalog) throws DBException {
getSchemaImpl().setCatalog(catalog);
}
/** Gets the catalog name of this schema snapshot.
* @return the catalog name, or <code>null</code> if this snapshot does
* not have a catalog name
*/
public DBIdentifier getCatalog() {
return getSchemaImpl().getCatalog();
}
/** Adds a new table to the schema snapshot.
* @param el the table to add
* @throws DBException if impossible
*/
public void addTable(TableElement el) throws DBException {
addTables(new TableElement[] {el});
}
/** Adds some new tables to the schema snapshot.
* @param els the tables to add
* @throws DBException if impossible
*/
public void addTables(final TableElement[] els) throws DBException {
for (int i = 0; i < els.length; i++) {
if (getTable(els[i].getName()) != null)
throwAddException("FMT_EXC_AddTable", els[i]); //NOI18N
if (els[i].getDeclaringSchema() == null)
els[i].setDeclaringSchema(this);
}
getSchemaImpl().changeTables(els, Impl.ADD);
}
/** Removes a table from the schema snapshot.
* @param el the table to remove
* @throws DBException if impossible
*/
public void removeTable(TableElement el) throws DBException {
removeTables(new TableElement[] {el});
}
/** Removes some tables from the schema snapshot.
* @param els the columns to remove
* @throws DBException if impossible
*/
public void removeTables(final TableElement[] els) throws DBException {
getSchemaImpl().changeTables(els, Impl.REMOVE);
}
/** Sets the tables for this schema snapshot.
* Previous tables are removed.
* @param els the new tables
* @throws DBException if impossible
*/
public void setTables(TableElement[] els) throws DBException {
if (els == null)
throw new NullPointerException(ResourceBundle.getBundle("org.netbeans.modules.dbschema.resources.Bundle").getString("NullTables")); //NOI18N
getSchemaImpl().changeTables(els, Impl.SET);
}
/** Gets all tables in this schema snapshot.
* @return the tables
*/
public TableElement[] getTables() {
return getSchemaImpl().getTables();
}
/** Finds a table by name.
* @param name the name of the table for which to look
* @return the element or <code>null</code> if not found
*/
public TableElement getTable(DBIdentifier name) {
return getSchemaImpl().getTable(name);
}
/** This method just throws localized exception. It is used during
* adding class element, which already exists in source.
* @param formatKey The message format key to localized bundle.
* @param element The element which can't be added
* @exception DBException is alway thrown from this method.
*/
private void throwAddException(String formatKey, TableElement element) throws DBException {
//MessageFormat format = new MessageFormat(ElementFormat.bundle.getString(formatKey));
String msg = /*format.format(new Object[] { */element.getName().getName();// });
throw new DBException(msg);
}
/** Getter for property url.
* @return Value of property url.
*/
public String getUrl() {
return getSchemaImpl().getUrl();
}
/** Setter for property url.
* @param url New value of property url.
*/
public void setUrl(String url) throws DBException {
getSchemaImpl().setUrl(url);
}
/** Getter for property username.
* @return Value of property username.
*/
public String getUsername() {
return getSchemaImpl().getUsername();
}
/** Setter for property username.
* @param username New value of property username.
*/
public void setUsername(String username) throws DBException {
getSchemaImpl().setUsername(username);
}
/** Getter for property driver.
* @return Value of property driver.
*/
public String getDriver() {
return getSchemaImpl().getDriver();
}
/** Setter for property driver.
* @param driver New value of property driver.
*/
public void setDriver(String driver) {
getSchemaImpl().setDriver(driver);
}
/** Getter for property databaseProductName.
* @return Value of property databaseProductName.
*/
public String getDatabaseProductName() {
return getSchemaImpl().getDatabaseProductName();
}
/** Setter for property databaseProductName.
* @param databaseProductName New value of property databaseProductName.
*/
public void setDatabaseProductName(String databaseProductName) throws DBException {
getSchemaImpl().setDatabaseProductName(databaseProductName);
}
/** Getter for property databaseProductVersion.
* @return Value of property databaseProductVersion.
*/
public String getDatabaseProductVersion() {
return getSchemaImpl().getDatabaseProductVersion();
}
/** Setter for property databaseProductVersion.
* @param databaseProductVersion New value of property databaseProductVersion.
*/
public void setDatabaseProductVersion(String databaseProductVersion) throws DBException {
getSchemaImpl().setDatabaseProductVersion(databaseProductVersion);
}
/** Getter for property driverName.
* @return Value of property driverName.
*/
public String getDriverName() {
return getSchemaImpl().getDriverName();
}
/** Setter for property driverName.
* @param driverName New value of property driverName.
*/
public void setDriverName(String driverName) throws DBException {
getSchemaImpl().setDriverName(driverName);
}
/** Getter for property driverVersion.
* @return Value of property driverVersion.
*/
public String getDriverVersion() {
return getSchemaImpl().getDriverVersion();
}
/** Setter for property driverVersion.
* @param driverVersion New value of property driverVersion.
*/
public void setDriverVersion(String driverVersion) throws DBException {
getSchemaImpl().setDriverVersion(driverVersion);
}
/** Saves the current schema to an XML file.
* @param filename the system-dependent filename
*/
public void save(String filename) {
setVersionNo(CURRENT_VERSION_NO);
try {
OutputStream s = new FileOutputStream(filename);
ObjectOutput o = new XMLOutputStream(s);
o.writeObject(this);
o.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
/** Saves the current schema to an XML file.
* @param s the output stream
*/
public void save(OutputStream s) {
setVersionNo(CURRENT_VERSION_NO);
try {
ObjectOutput o = new XMLOutputStream(s);
o.writeObject(this);
o.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
/** Pluggable behaviour for schema elements.
* @see SchemaElement
*/
public static interface Impl extends DBElement.Impl {
/** Gets the parsing status of the element.
* This is a non-blocking operation.
* @return one of {@link #STATUS_NOT}, {@link #STATUS_ERROR},
* {@link #STATUS_PARTIAL}, or {@link #STATUS_OK}
*/
public int getStatus();
/** Sets the schema name of this schema snapshot.
* @param id the schema name, or <code>null</code>
* @exception DBException if the operation cannot proceed
*/
public void setSchema(DBIdentifier id) throws DBException;
/** Get the schema name of this schema snapshot.
* @return the schema name, or <code>null</code> if this snapshot does
* not have a schema name
*/
public DBIdentifier getSchema();
/** Sets the catalog name of this schema snapshot.
* @param id the catalog name, or <code>null</code>
* @exception DBException if the operation cannot proceed
*/
public void setCatalog(DBIdentifier id) throws DBException;
/** Gets the catalog name of this schema snapshot.
* @return the catalog name, or <code>null</code> if this snapshot does
* not have a catalog name
*/
public DBIdentifier getCatalog();
/** Change the set of tables.
* @param elems the tables to change
* @param action one of {@link #ADD}, {@link #REMOVE}, or {@link #SET}
* @exception DBException if the action cannot be handled
*/
public void changeTables(TableElement[] elems, int action) throws DBException;
/** Gets all tables.
* @return the tables
*/
public TableElement[] getTables();
/** Finds a table by name.
* @param name the name for which to look
* @return the table, or <code>null</code> if it does not exist
*/
public TableElement getTable(DBIdentifier name);
/** Getter for property url.
* @return Value of property url.
*/
public String getUrl();
/** Setter for property url.
* @param url New value of property url.
*/
public void setUrl(String url) throws DBException;
/** Getter for property username.
* @return Value of property username.
*/
public String getUsername();
/** Setter for property username.
* @param username New value of property username.
*/
public void setUsername(String username) throws DBException;
/** Getter for property driver.
* @return Value of property driver.
*/
public String getDriver();
/** Setter for property driver.
* @param driver New value of property driver.
*/
public void setDriver(String driver);
/** Getter for property databaseProductName.
* @return Value of property databaseProductName.
*/
public String getDatabaseProductName();
/** Setter for property databaseProductName.
* @param databaseProductName New value of property databaseProductName.
*/
public void setDatabaseProductName(String databaseProductName) throws DBException;
/** Getter for property databaseProductVersion.
* @return Value of property databaseProductVersion.
*/
public String getDatabaseProductVersion();
/** Setter for property databaseProductVersion.
* @param databaseProductVersion New value of property databaseProductVersion.
*/
public void setDatabaseProductVersion(String databaseProductVersion) throws DBException;
/** Getter for property driverName.
* @return Value of property driverName.
*/
public String getDriverName();
/** Setter for property driverName.
* @param driverName New value of property driverName.
*/
public void setDriverName(String driverName) throws DBException;
/** Getter for property driverVersion.
* @return Value of property driverVersion.
*/
public String getDriverVersion();
/** Setter for property driverVersion.
* @param driverVersion New value of property driverVersion.
*/
public void setDriverVersion(String driverVersion) throws DBException;
}
/** Memory based implementation of the element factory.
*/
static final class Memory extends DBElement.Memory implements Impl {
/** collection of tables */
private DBMemoryCollection.Table tables;
private DBIdentifier _catalog;
private DBIdentifier _schema;
private int _status;
private String _url;
private String _username;
private String _driver;
private String _databaseProductName;
private String _databaseProductVersion;
private String _driverName;
private String _driverVersion;
/** Default constructor
*/
public Memory() {
super();
}
/** Copy constructor.
* @param el element to copy from
*/
public Memory(SchemaElement el) {
super(el);
_catalog = el.getCatalog();
_schema = el.getSchema();
_status = el.getStatus();
_url = el.getUrl();
_username = el.getUsername();
_driver = el.getDriver();
_databaseProductName = el.getDatabaseProductName();
_databaseProductVersion = el.getDatabaseProductVersion();
_driverName = el.getDriverName();
_driverVersion = el.getDriverVersion();
}
/** Late initialization of initialization of copy elements.
*/
public void copyFrom(SchemaElement copyFrom) throws DBException {
changeTables(copyFrom.getTables(), SET);
}
/** Changes set of elements.
* @param elems elements to change
* @exception SourceException if the action cannot be handled
*/
public synchronized void changeTables(TableElement[] elems, int action) throws DBException {
initTables();
tables.change(elems, action);
}
/** Gets all tables.
* @return the tables
*/
public synchronized TableElement[] getTables() {
initTables();
return (TableElement[]) tables.getElements();
}
/** Finds a table with given name.
* @param name the name of table for which to look
* @return the element or null if table with such name does not exist
*/
public synchronized TableElement getTable(DBIdentifier name) {
initTables();
return (TableElement) tables.getElement(name);
}
/** Initializes the collection of tables.
*/
void initTables() {
if (tables == null)
tables = new DBMemoryCollection.Table(this);
}
/** Getter for the associated schema
* @return the schema element for this impl
*/
final SchemaElement getSchemaElement() {
return (SchemaElement) _element;
}
/** Gets the parsing status of the element.
* This is a non-blocking operation.
* @return one of {@link #STATUS_NOT}, {@link #STATUS_ERROR}, {@link
* #STATUS_PARTIAL}, or {@link #STATUS_OK}
*/
public int getStatus() {
return _status;
}
public void setSchema(DBIdentifier id) throws DBException {
DBIdentifier old = _schema;
_schema = id;
firePropertyChange (PROP_SCHEMA, old, id);
}
public DBIdentifier getSchema() {
if (_schema == null) // lazy initialization !?
_schema = DBIdentifier.create(""); //NOI18N
return _schema;
}
public void setCatalog(DBIdentifier id) throws DBException {
DBIdentifier old = _catalog;
_catalog = id;
firePropertyChange (PROP_CATALOG, old, id);
}
public DBIdentifier getCatalog() {
if (_catalog == null) // lazy initialization !?
_catalog = DBIdentifier.create(""); //NOI18N
return _catalog;
}
public String getUrl() {
return _url;
}
public void setUrl(String url) throws DBException{
_url = url;
}
public String getUsername() {
return _username;
}
public void setUsername(String username) throws DBException{
_username = username;
}
public String getDriver() {
return _driverName;
}
public void setDriver(String driver){
_driver = driver;
}
public String getDatabaseProductName() {
return _databaseProductName;
}
public void setDatabaseProductName(String databaseProductName) throws DBException {
_databaseProductName = databaseProductName;
}
public String getDatabaseProductVersion() {
return _databaseProductVersion;
}
public void setDatabaseProductVersion(String databaseProductVersion) throws DBException{
_databaseProductVersion = databaseProductVersion;
}
public String getDriverName() {
return _driverName;
}
public void setDriverName(String driverName) throws DBException {
_driverName = driverName;
}
public String getDriverVersion() {
return _driverVersion;
}
public void setDriverVersion(String driverVersion) throws DBException {
_driverVersion = driverVersion;
}
}
}