Java tutorial
/*---------------- FILE HEADER KALYPSO ------------------------------------------ * * This file is part of kalypso. * Copyright (C) 2004 by: * * Technical University Hamburg-Harburg (TUHH) * Institute of River and coastal engineering * Denickestrae 22 * 21073 Hamburg, Germany * http://www.tuhh.de/wb * * and * * Bjoernsen Consulting Engineers (BCE) * Maria Trost 3 * 56070 Koblenz, Germany * http://www.bjoernsen.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: * * E-Mail: * belger@bjoernsen.de * schlienger@bjoernsen.de * v.doemming@tuhh.de * * ---------------------------------------------------------------------------*/ package org.kalypso.model.wspm.pdb.db; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.widgets.Shell; import org.hibernate.jdbc.Work; import org.kalypso.commons.patternreplace.ConstantReplacer; import org.kalypso.commons.patternreplace.PatternInputReplacer; import org.kalypso.contribs.eclipse.ui.progress.ProgressUtilities; import org.kalypso.core.status.StatusDialog; import org.kalypso.model.wspm.pdb.connect.IPdbConnection; import org.kalypso.model.wspm.pdb.connect.PDBRole; import org.kalypso.model.wspm.pdb.db.version.UpdateScript; import org.kalypso.model.wspm.pdb.db.version.UpdateScriptExtenions; import org.kalypso.model.wspm.pdb.db.version.UpdateScriptPageData; import org.kalypso.model.wspm.pdb.internal.WspmPdbCorePlugin; import org.kalypso.model.wspm.pdb.internal.i18n.Messages; import org.kalypso.model.wspm.pdb.internal.update.SqlWork; import org.kalypso.model.wspm.pdb.internal.update.UpdateScriptWizard; import org.kalypso.model.wspm.pdb.internal.update.WorkRunnable; import org.osgi.framework.Version; import com.vividsolutions.jts.geom.Envelope; /** * @author Gernot Belger */ public class PdbUpdater { enum DbState { uptodate, empty, dbOutdated, kalypsoOutdated } private final static String WINDOW_TITLE = Messages.getString("PdbUpdater_0"); //$NON-NLS-1$ private static final String STR_CONNECTION_IMPOSSIBLE = Messages.getString("PdbUpdater_1"); //$NON-NLS-1$ private static final String STR_CREATE = STR_CONNECTION_IMPOSSIBLE + Messages.getString("PdbUpdater_2"); //$NON-NLS-1$ private static final String STR_UPDATE = STR_CONNECTION_IMPOSSIBLE + Messages.getString("PdbUpdater_3"); //$NON-NLS-1$ private final IPdbConnection m_connection; private final Shell m_shell; public PdbUpdater(final IPdbConnection connection, final Shell shell) { m_connection = connection; m_shell = shell; } public IStatus execute() { /* Check version */ final PdbInfo info = m_connection.getInfo(); final boolean isSuperuser = checkSuperuser(); final Version version = info.getVersion(); final DbState state = checkDbState(version); switch (state) { case uptodate: return Status.OK_STATUS; case empty: if (isSuperuser) return handleCreate(); else return handleShouldCreate(); case kalypsoOutdated: final String msg = String.format(STR_CONNECTION_IMPOSSIBLE + Messages.getString("PdbUpdater_4"), //$NON-NLS-1$ version); return new Status(IStatus.ERROR, WspmPdbCorePlugin.PLUGIN_ID, msg); case dbOutdated: if (isSuperuser) return handleUpdate(version); else return handleShouldUpdate(version); } throw new IllegalStateException(); } private DbState checkDbState(final Version version) { // TODO: check, if database is empty // TODO: check, if it is a spatial database if (version == null) return DbState.empty; if (PdbInfo.CURRENT_VERSION.equals(version)) return DbState.uptodate; if (version.compareTo(PdbInfo.CURRENT_VERSION) > 0) return DbState.kalypsoOutdated; if (version.compareTo(PdbInfo.CURRENT_VERSION) < 0) return DbState.dbOutdated; throw new IllegalStateException(); } private boolean checkSuperuser() { return m_connection.getRole() == PDBRole.superuser; } private IStatus handleCreate() { /* ask user what to do */ final String msg = String.format(Messages.getString("PdbUpdater_5"), STR_CREATE); //$NON-NLS-1$ final MessageDialog dialog = new MessageDialog(m_shell, WINDOW_TITLE, null, msg, MessageDialog.CONFIRM, new String[] { Messages.getString("PdbUpdater_6"), IDialogConstants.CANCEL_LABEL }, 1); //$NON-NLS-1$ if (dialog.open() != Window.OK) return Status.CANCEL_STATUS; /* Do update */ final String dbType = m_connection.getSettings().getType(); final UpdateScript createScript = UpdateScriptExtenions.getScript(new Version(0, 0, 0), dbType); if (createScript == null) throw new IllegalStateException("Missing create script"); //$NON-NLS-1$ final UpdateScript[] scripts = new UpdateScript[] { createScript }; return executeScripts(scripts, Messages.getString("PdbUpdater_7")); //$NON-NLS-1$ } private IStatus handleShouldCreate() { final String msg = String.format(Messages.getString("PdbUpdater_8"), STR_CREATE, IPdbConnection.SUPERUSER); //$NON-NLS-1$ MessageDialog.openWarning(m_shell, WINDOW_TITLE, msg); return Status.CANCEL_STATUS; } private IStatus handleUpdate(final Version version) { // 0) ggf. check preconditions /* ask user what to do */ final String baseMsg = String.format(STR_UPDATE, version, PdbInfo.CURRENT_VERSION); final String msg = baseMsg + Messages.getString("PdbUpdater_9"); //$NON-NLS-1$ final MessageDialog dialog = new MessageDialog(m_shell, WINDOW_TITLE, null, msg, MessageDialog.CONFIRM, new String[] { Messages.getString("PdbUpdater_10"), IDialogConstants.CANCEL_LABEL }, 1); //$NON-NLS-1$ if (dialog.open() != Window.OK) return Status.CANCEL_STATUS; /* Do update */ final String dbType = m_connection.getSettings().getType(); final UpdateScript[] scripts = UpdateScriptExtenions.getUpdateScripts(version, dbType); if (scripts == null) throw new IllegalStateException("Missing create script"); //$NON-NLS-1$ return executeScripts(scripts, Messages.getString("PdbUpdater_11")); //$NON-NLS-1$ } private IStatus handleShouldUpdate(final Version version) { final String baseMsg = String.format(STR_UPDATE, version, PdbInfo.CURRENT_VERSION); final String msg = String.format(Messages.getString("PdbUpdater_12"), baseMsg, IPdbConnection.SUPERUSER); //$NON-NLS-1$ MessageDialog.openWarning(m_shell, WINDOW_TITLE, msg); return Status.CANCEL_STATUS; } private IStatus executeScripts(final UpdateScript[] scripts, final String windowTitle) { try { final Properties replaceVariables = determineVariables(scripts); final String[] sqls = loadSql(scripts, replaceVariables); if (sqls == null) return Status.OK_STATUS; final Work operation = new SqlWork(sqls); final WorkRunnable runnable = new WorkRunnable(m_connection, operation); final IStatus status = ProgressUtilities.busyCursorWhile(runnable); if (!status.isOK()) new StatusDialog(m_shell, status, windowTitle).open(); m_connection.updateInfo(); return status; } catch (final CoreException e) { if (!e.getStatus().matches(IStatus.CANCEL)) e.printStackTrace(); return e.getStatus(); } } private String[] loadSql(final UpdateScript[] scripts, final Properties variables) { try { final PatternInputReplacer<Object> inputReplacer = configurePatternReplacer(variables); final Collection<String> sql = new ArrayList<>(); for (final UpdateScript script : scripts) { final String[] sqlStatements = script.loadSQL(); for (final String statement : sqlStatements) { final String resolvedStatement = inputReplacer.replaceTokens(statement, null); sql.add(resolvedStatement); } } return sql.toArray(new String[sql.size()]); } catch (final IOException e) { e.printStackTrace(); throw new IllegalStateException(Messages.getString("PdbUpdater_13"), e); //$NON-NLS-1$ } } private PatternInputReplacer<Object> configurePatternReplacer(final Properties variables) { final PatternInputReplacer<Object> inputReplacer = new PatternInputReplacer<>("${", "}"); //$NON-NLS-1$ //$NON-NLS-2$ final Set<String> names = variables.stringPropertyNames(); for (final String name : names) { final String value = variables.getProperty(name); // REMARK: '\' causes problem, at least with postgres, and is only every used in pathes. So we replace it with '/' here. final String cleanValue = value.replace('\\', '/'); inputReplacer.addReplacer(new ConstantReplacer(name, cleanValue)); } return inputReplacer; } private Properties determineVariables(final UpdateScript[] scripts) throws CoreException { final Properties properties = new Properties(); /* some defaults */ properties.setProperty(PdbInfo.PROPERTY_DOCUMENT_SERVER, "http://example.com/document/path/"); //$NON-NLS-1$ properties.setProperty(PdbInfo.PROPERTY_DEM_SERVER, "P:/data/terrain/"); //$NON-NLS-1$ properties.setProperty(PdbInfo.PROPERTY_SRID, "31468"); //$NON-NLS-1$ /* Add depending variables */ final String srid = properties.getProperty(PdbInfo.PROPERTY_SRID); final Envelope domainOfValidity = m_connection.getCrsEnvelope(Integer.valueOf(srid)); properties.setProperty(PdbInfo.PROPERTY_SRS_MIN_Z, String.format(Locale.US, "%f", -1000.0)); //$NON-NLS-1$ properties.setProperty(PdbInfo.PROPERTY_SRS_MAX_Z, String.format(Locale.US, "%f", 10000.0)); //$NON-NLS-1$ if (domainOfValidity != null) { properties.setProperty(PdbInfo.PROPERTY_SRS_MIN_X, String.format(Locale.US, "%f", domainOfValidity.getMinX())); //$NON-NLS-1$ properties.setProperty(PdbInfo.PROPERTY_SRS_MAX_X, String.format(Locale.US, "%f", domainOfValidity.getMaxX())); //$NON-NLS-1$ properties.setProperty(PdbInfo.PROPERTY_SRS_MIN_Y, String.format(Locale.US, "%f", domainOfValidity.getMinY())); //$NON-NLS-1$ properties.setProperty(PdbInfo.PROPERTY_SRS_MAX_Y, String.format(Locale.US, "%f", domainOfValidity.getMaxY())); //$NON-NLS-1$ } final PdbInfo info = m_connection.getInfo(); if (info != null) { final Entry<String, String>[] entries = info.getEntries(); for (final Entry<String, String> entry : entries) properties.setProperty(entry.getKey(), entry.getValue()); } /* Ask user for missing variables */ final IWizardPage[] pages = findUpdatePages(scripts, properties); if (pages.length > 0) { final UpdateScriptWizard wizard = new UpdateScriptWizard(pages); wizard.setWindowTitle(WINDOW_TITLE); final int open = new WizardDialog(m_shell, wizard).open(); if (open != Window.OK) throw new CoreException(Status.CANCEL_STATUS); } updateDependendProperties(properties); return properties; } private IWizardPage[] findUpdatePages(final UpdateScript[] scripts, final Properties properties) throws CoreException { final UpdateScriptPageData data = new UpdateScriptPageData(properties); // TRICKY: the page name serves as id for the page: if two scripts have pages with the same name, // the more recent script should win. Altogether the order of pages should be preserved. final Map<String, IWizardPage> pages = new LinkedHashMap<>(); for (final UpdateScript updateScript : scripts) { final IWizardPage[] scriptPages = updateScript.createVariablePages(data); for (final IWizardPage page : scriptPages) pages.put(page.getName(), page); } return pages.values().toArray(new IWizardPage[pages.size()]); } private void updateDependendProperties(final Properties properties) { // FIXME: use the chosen srs in order to set these properties properties.setProperty(PdbInfo.PROPERTY_SRS_X_NAME, "X"); //$NON-NLS-1$ properties.setProperty(PdbInfo.PROPERTY_SRS_Y_NAME, "Y"); //$NON-NLS-1$ // CRS.decode(srid).getCoordinateSystem().getAxis( 0 ).getUnit() // for geographic crs use the following // properties.setProperty( PdbInfo.PROPERTY_SRS_XName", "Longitude" ); // X is longitude! // properties.setProperty( PdbInfo.PROPERTY_SRS_YName", "Latitude" ); // Y is latitude! // maybe change (enlarge) x and y tolerance for geographic crs properties.setProperty(PdbInfo.PROPERTY_SRS_TOL_X, String.format(Locale.US, "%f", 0.0005)); //$NON-NLS-1$ properties.setProperty(PdbInfo.PROPERTY_SRS_TOL_Y, String.format(Locale.US, "%f", 0.0005)); //$NON-NLS-1$ properties.setProperty(PdbInfo.PROPERTY_SRS_TOL_Z, String.format(Locale.US, "%f", 0.0005)); //$NON-NLS-1$ properties.setProperty(PdbInfo.PROPERTY_SRS_Z_NAME, "Z"); // equal for all coordinate systems //$NON-NLS-1$ } }