/*******************************************************************************
* Copyright (c) 2007-2008 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributor:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.seam.ui.views;
import java.lang.reflect.Method;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.progress.WorkbenchJob;
import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.JDBCReaderFactory;
import org.hibernate.cfg.Settings;
import org.hibernate.cfg.reveng.dialect.MetaDataDialect;
import org.hibernate.console.ConsoleConfiguration;
import org.hibernate.console.ImageConstants;
import org.hibernate.console.execution.ExecutionContext;
import org.hibernate.eclipse.console.utils.EclipseImages;
import org.hibernate.mapping.Table;
import org.jboss.tools.hibernate.runtime.spi.IConfiguration;
import org.jboss.tools.seam.ui.SeamGuiPlugin;
import org.jboss.tools.seam.ui.internal.reveng.JDBCTablesColumnsReader;
import org.jboss.tools.seam.ui.internal.reveng.TablesColumnsCollector;
/**
* Database tree viewer with three-level structure (till Tables)
* @author Dmitry Geraskov
*/
public class DBTablesViewer extends TreeViewer {
private String connectionErrorMessage = "Couldn't connect to Database"; //$NON-NLS-1$
private Image catalog = EclipseImages.getImageDescriptor(ImageConstants.DATABASE).createImage();
private Image schema = EclipseImages.getImageDescriptor(ImageConstants.SCHEMA).createImage();
private Image table = EclipseImages.getImageDescriptor(ImageConstants.TABLE).createImage();
public class Element{
private String name;
protected String defaultLabel;
Element(String name){
this.name = name;
}
public String getName(){
return name;
}
public String getLabel(){
return name == null ? defaultLabel : name;
}
}
public class Catalog extends Element{
public static final String DEF_CATALOG_NAME = "<Default catalog>"; //$NON-NLS-1$
Catalog(String name){
super(name);
defaultLabel = DEF_CATALOG_NAME;
}
}
public class Schema extends Element{
public static final String DEF_SCHEMA_NAME = "<Default schema>"; //$NON-NLS-1$
private Catalog parent;
Schema(String name, Catalog parent){
super(name);
this.parent = parent;
defaultLabel = DEF_SCHEMA_NAME;
}
public Catalog getParent(){
return parent;
}
}
public DBTablesViewer(Tree tree){
super(tree);
setContentProvider(createContentProvider());
setLabelProvider(createLabelProvider());
}
public DBTablesViewer(Composite parent) {
super(parent);
}
/**
* @return ITreeContentProvider
*/
protected ITreeContentProvider createContentProvider() {
return new ITreeContentProvider(){
private IConfiguration cfg = null;
private Settings buildSettings = null;
private String placeHolder = "Pending..."; //$NON-NLS-1$
private String conErrorItem = '<' + connectionErrorMessage + '>';
private final Object[] NO_CHILDREN = new Object[0];
private static final int BEGIN_STATE = 0;
private static final int CHILDREN_FETCHED = 1;
private static final int CONNECTION_ERROR = 2;
private static final int LOADING_IN_PROGRESS = 3;
private int connectionState = BEGIN_STATE;
private TablesColumnsCollector tablesCollector;
private Object[] getCatalogs(){
if (connectionState == LOADING_IN_PROGRESS){
return new String[]{placeHolder};
}
if (connectionState == CONNECTION_ERROR){
return new String[]{connectionErrorMessage};
}
List catalogNames = tablesCollector.getCatalogNames();
Element[] catalogs = new Element[catalogNames.size()];
for (int i = 0; i < catalogs.length; i++) {
String catalogName = (String) catalogNames.get(i);
if (catalogName == null || "".equals(catalogName)) catalogName = null; //$NON-NLS-1$
catalogs[i] = new Catalog(catalogName);
}
return catalogs;
}
private Object[] getSchemas(Catalog catalog){
List schemaNames = tablesCollector.getMatchingSchemaNames(catalog.getName(), buildSettings.getDefaultSchemaName());
Element[] schemas = new Element[schemaNames.size()];
for (int i = 0; i < schemaNames.size(); i++) {
String schemaName = (String) schemaNames.get(i);
if (schemaName == null || "".equals(schemaName)) schemaName = null; //$NON-NLS-1$
schemas[i] = new Schema( schemaName, catalog);
}
return schemas;
}
private Object[] getTables(Schema schema){
List tableNames = tablesCollector.getMatchingTablesNames(schema.getParent().getName(), schema.getName(), ""); //$NON-NLS-1$
Table[] tables = new Table[tableNames.size()];
for (int i = 0; i < tables.length; i++) {
tables[i] = new Table((String) tableNames.get(i));
tables[i].setCatalog(schema.getParent().getName());
tables[i].setSchema(schema.getName());
}
return tables;
}
public Object[] getChildren(Object parent) {
if (parent instanceof Catalog) {
return getSchemas((Catalog)parent);
}
if (parent instanceof Schema) {
Schema schema = (Schema)parent;
return getTables(schema);
}
return NO_CHILDREN;
}
public Object getParent(Object element) {
if (element instanceof Schema){
return ((Schema)element).getParent();
}
return null;
}
public boolean hasChildren(Object parent) {
return parent instanceof Element;
}
public Object[] getElements(Object inputElement) {
if (buildSettings == null) return new String[]{conErrorItem};
if (connectionState == BEGIN_STATE){
tablesCollector = new TablesColumnsCollector(true);
if (connectionState == BEGIN_STATE)
connectionState = LOADING_IN_PROGRESS;
WorkbenchJob job = new WorkbenchJob("Fetching database structure") { //$NON-NLS-1$
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
try{
MetaDataDialect realMetaData = JDBCReaderFactory.newMetaDataDialect(buildSettings
.getDialect(), cfg.getProperties());
JDBCTablesColumnsReader reader = new JDBCTablesColumnsReader(realMetaData,
buildSettings.getConnectionProvider(), buildSettings.getSQLExceptionConverter());
reader.readDatabaseTables(tablesCollector, buildSettings.getDefaultCatalogName(), buildSettings.getDefaultSchemaName());
connectionState = CHILDREN_FETCHED;
} catch (JDBCException e){
connectionState = CONNECTION_ERROR;
}
DBTablesViewer.this.remove(placeHolder);
DBTablesViewer.this.refresh();
return Status.OK_STATUS;
}};
job.schedule();
}
return getCatalogs();
}
public void dispose() {}
/**
* Supported input types are:
* org.hibernate.console.ConsoleConfiguration,
* org.hibernate.cfg.Settings.
*/
public void inputChanged(Viewer viewer, Object oldInput,
Object newInput) {
if (newInput == oldInput
&& connectionState != CONNECTION_ERROR) return;
if (newInput instanceof ConsoleConfiguration) {
ConsoleConfiguration cc = (ConsoleConfiguration) newInput;
try{
cc.build();
cfg = cc.getConfiguration();
cc.getExecutionContext().execute(new ExecutionContext.Command() {
public Object execute() {
try {
Method method = cfg.getClass().getMethod("getTarget", new Class[] {});
Configuration config = (Configuration)method.invoke(cfg, new Object[] {});
Settings newSettings = config.buildSettings();
if (!newSettings.equals(buildSettings)){
buildSettings = newSettings;
connectionState = BEGIN_STATE;
}
}
catch (Exception e) {
SeamGuiPlugin.getPluginLog().logError(e);
}
return null;
}});
} catch (HibernateException e){
connectionState = CONNECTION_ERROR;
}
}
}
};
}
protected LabelProvider createLabelProvider(){
return new LabelProvider(){
@Override
public void dispose() {
catalog.dispose();
schema.dispose();
table.dispose();
}
@Override
public Image getImage(Object element) {
if (element instanceof Catalog){
return catalog;
}
if (element instanceof Schema){
return schema;
}
if (element instanceof Table){
return table;
}
return null;
}
@Override
public String getText(Object element) {
if (element instanceof Element){
return ((Element)element).getLabel();
}
if (element instanceof Table){
return ((Table)element).getName();
}
return super.getText(element);
}
};
}
public void setConnectionErrorMessage(String connectionErrorMessage) {
this.connectionErrorMessage = connectionErrorMessage;
}
}