/* * Copyright (c) 2017 wetransform GmbH * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * wetransform GmbH <http://www.wetransform.to> */ package eu.esdihumboldt.hale.io.jdbc.ui; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.text.MessageFormat; import javax.xml.namespace.QName; import org.eclipse.jface.fieldassist.ContentProposalAdapter; import org.eclipse.jface.fieldassist.ControlDecoration; import org.eclipse.jface.fieldassist.FieldDecorationRegistry; import org.eclipse.jface.fieldassist.TextContentAdapter; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import eu.esdihumboldt.hale.common.core.io.ImportProvider; import eu.esdihumboldt.hale.common.core.io.Value; import eu.esdihumboldt.hale.common.schema.SchemaSpaceID; import eu.esdihumboldt.hale.common.schema.model.TypeDefinition; import eu.esdihumboldt.hale.io.jdbc.JDBCProvider; import eu.esdihumboldt.hale.io.jdbc.JDBCUtil; import eu.esdihumboldt.hale.io.jdbc.SQLSchemaReader; import eu.esdihumboldt.hale.ui.HaleUI; import eu.esdihumboldt.hale.ui.common.CommonSharedImages; import eu.esdihumboldt.hale.ui.io.IOWizard; import eu.esdihumboldt.hale.ui.io.config.AbstractConfigurationPage; import eu.esdihumboldt.hale.ui.service.project.ProjectVariablesContentProposalProvider; import eu.esdihumboldt.hale.ui.service.schema.SchemaService; /** * Configuration page for specifying SQL query and type name. * * @author Simon Templer */ public class SQLSchemaPage extends AbstractConfigurationPage<ImportProvider, IOWizard<ImportProvider>> { private Text typeName; private Text sqlQuery; private final ProjectVariablesContentProposalProvider contentProposalProvider = new ProjectVariablesContentProposalProvider( true); /** * Default constructor. */ public SQLSchemaPage() { super("sql.schema"); setTitle("SQL Query"); setDescription("Please specify an SQL query and a type name that should represent it"); setPageComplete(false); } @Override public void enable() { // nothing to do } @Override public void disable() { // nothing to do } @Override public boolean updateConfiguration(ImportProvider provider) { if (typeName != null) { provider.setParameter(SQLSchemaReader.PARAM_TYPE_NAME, Value.of(typeName.getText())); } if (sqlQuery != null) { provider.setParameter(SQLSchemaReader.PARAM_SQL, Value.of(new eu.esdihumboldt.hale.common.core.io.Text(sqlQuery.getText()))); } return updateState(true); } private boolean updateState(boolean runQuery) { boolean typeValid = false; boolean sqlValid = false; String error = null; String message = null; if (typeName != null) { // check type name String type = typeName.getText(); typeValid = type != null && !type.isEmpty(); if (typeValid) { // check if the name already exists in the source schema SchemaService schemas = HaleUI.getServiceProvider().getService(SchemaService.class); if (schemas != null) { TypeDefinition existing = schemas.getSchemas(SchemaSpaceID.SOURCE) .getType(new QName(SQLSchemaReader.NAMESPACE, type)); if (existing != null) { typeValid = false; error = "An SQL query with this name already exists"; } } // also test for specific characters? } } if (sqlQuery != null) { // check SQL query String sql = sqlQuery.getText(); sqlValid = sql != null && !sql.isEmpty(); if (sqlValid) { String processedQuery; try { processedQuery = JDBCUtil.replaceVariables(sql, HaleUI.getServiceProvider()); } catch (Exception e) { error = e.getLocalizedMessage(); sqlValid = false; processedQuery = null; } // check if processed SQL query can be executed if (runQuery && processedQuery != null) { ImportProvider provider = getWizard().getProvider(); if (provider != null && provider instanceof JDBCProvider) { Connection connection = null; try { try { connection = ((JDBCProvider) provider).getConnection(); } catch (SQLException e) { sqlValid = false; error = "Could not establish database connection: " + e.getLocalizedMessage(); } if (connection != null) { try { Statement statement = JDBCUtil.createReadStatement(connection, 1); try { ResultSet result = statement.executeQuery(processedQuery); int columnCount = result.getMetaData().getColumnCount(); if (columnCount <= 0) { sqlValid = false; error = "Query result does not have any columns"; } else { if (columnCount == 1) { message = "Successfully tested query. It yields a result with a single column."; } else { message = MessageFormat.format( "Successfully tested query. It yields a result with {0} columns.", columnCount); } } } catch (SQLException e) { sqlValid = false; error = "Error querying database: " + e.getMessage(); } finally { statement.close(); } } catch (SQLException e) { sqlValid = false; error = "Could not create database statement: " + e.getMessage(); } } } finally { if (connection != null) { try { connection.close(); } catch (SQLException e) { // ignore } } } } } } } boolean complete = typeValid && sqlValid; if (complete) { error = null; } else if (!typeValid && error == null) { error = "Please provide a name for the query"; } else if (error == null) { error = "Please specify the SQL query to use"; } setMessage(message); setErrorMessage(error); setPageComplete(complete); return complete; } @Override protected void createContent(Composite page) { GridLayoutFactory.swtDefaults().numColumns(2).applyTo(page); GridDataFactory labelFactory = GridDataFactory.swtDefaults().align(SWT.END, SWT.CENTER); // type name Label typeLabel = new Label(page, SWT.NONE); labelFactory.applyTo(typeLabel); typeLabel.setText("Query name:"); typeName = new Text(page, SWT.SINGLE | SWT.BORDER); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false) .applyTo(typeName); typeName.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { updateState(false); } }); // SQL query Label sqlLabel = new Label(page, SWT.NONE); labelFactory.applyTo(sqlLabel); sqlLabel.setText("SQL query:"); sqlQuery = new Text(page, SWT.MULTI | SWT.BORDER | SWT.WRAP | SWT.V_SCROLL); GridDataFactory.fillDefaults().grab(true, true).applyTo(sqlQuery); sqlQuery.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { updateState(false); } }); ContentProposalAdapter adapter = new ContentProposalAdapter(sqlQuery, new TextContentAdapter(), contentProposalProvider, ProjectVariablesContentProposalProvider.CTRL_SPACE, new char[] { '{' }); adapter.setAutoActivationDelay(0); final ControlDecoration infoDeco = new ControlDecoration(sqlQuery, SWT.TOP | SWT.LEFT); infoDeco.setDescriptionText("Type Ctrl+Space for project variable content assistance"); infoDeco.setImage(FieldDecorationRegistry.getDefault() .getFieldDecoration(FieldDecorationRegistry.DEC_INFORMATION).getImage()); infoDeco.setShowOnlyOnFocus(true); // button for testing query Button button = new Button(page, SWT.BORDER | SWT.FLAT); GridDataFactory.swtDefaults().align(SWT.END, SWT.CENTER).span(2, 1).applyTo(button); button.setImage(CommonSharedImages.getImageRegistry().get(CommonSharedImages.IMG_PLAY)); button.setText("Test query"); button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateState(true); } }); updateState(false); } }