/* * SonarLint for Eclipse * Copyright (C) 2015-2017 SonarSource SA * sonarlint@sonarsource.com * * This program 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 3 of the License, or (at your option) any later version. * * This program 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 program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonarlint.eclipse.ui.internal.server.wizard; import java.net.MalformedURLException; import java.net.URL; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.equinox.security.storage.StorageException; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.fieldassist.ContentProposalAdapter; import org.eclipse.jface.fieldassist.IContentProposalListener2; import org.eclipse.jface.fieldassist.TextContentAdapter; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; 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 org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; import org.sonarlint.eclipse.core.SonarLintLogger; import org.sonarlint.eclipse.core.internal.SonarLintCorePlugin; import org.sonarlint.eclipse.core.internal.server.IServer; import org.sonarlint.eclipse.core.internal.server.ServersManager; import org.sonarlint.eclipse.core.internal.utils.StringUtils; import org.sonarlint.eclipse.ui.internal.Messages; import org.sonarlint.eclipse.ui.internal.SonarLintImages; import org.sonarlint.eclipse.ui.internal.SonarLintUiPlugin; public class ServerLocationWizardPage extends WizardPage { private static final String DEFAULT_URL_SUGGESTION = "https://"; private static final String ERROR_READING_SECURE_STORAGE = "Error reading secure storage"; private final IServer server; private Text serverIdText; private Text serverUrlText; private Text organizationText; private Text serverUsernameText; private Text serverPasswordText; private IStatus status; private final boolean edit; private boolean serverIdManuallyChanged; private ModifyListener idModifyListener; private final String defaultServerId; public ServerLocationWizardPage() { this((IServer) null); } public ServerLocationWizardPage(String defaultServerId) { this((IServer) null, defaultServerId); } public ServerLocationWizardPage(IServer sonarServer) { this(sonarServer, null); } public ServerLocationWizardPage(IServer sonarServer, String defaultServerId) { super("server_location_page", "SonarQube Server Configuration", SonarLintImages.IMG_WIZBAN_NEW_SERVER); this.edit = sonarServer != null; this.server = sonarServer; this.defaultServerId = defaultServerId; } /** * @see org.eclipse.jface.dialogs.IDialogPage#createControl(Composite) */ @Override public void createControl(Composite parent) { final FormToolkit toolkit = new FormToolkit(parent.getDisplay()); parent.addDisposeListener(e -> toolkit.dispose()); final ScrolledForm form = toolkit.createScrolledForm(parent); form.setBackground(parent.getBackground()); GridLayout layout = new GridLayout(); layout.numColumns = 3; layout.verticalSpacing = 9; form.getBody().setLayout(layout); GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); form.setLayoutData(layoutData); // SonarQube Server URL createServerUrlField(form); // Sonar Server Username/Token createUsernameField(parent, form); createOpenSecurityPageButton(form.getBody()); // Sonar Server password createPasswordField(form); createOrganizationField(form); createServerIdField(form); // Test connection button createTestConnectionButton(form.getBody()); if (edit) { dialogChanged(); } Dialog.applyDialogFont(parent); setControl(form.getBody()); } private void createOrganizationField(final ScrolledForm form) { Label labelOrganization = new Label(form.getBody(), SWT.NULL); labelOrganization.setText("Organization:"); organizationText = new Text(form.getBody(), SWT.BORDER | SWT.SINGLE); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; organizationText.setLayoutData(gd); if (edit) { organizationText.setText(StringUtils.defaultString(server.getOrganization())); } else { organizationText.setText(""); } organizationText.addModifyListener(e -> suggestServerId()); ContentProposalAdapter contentProposalAdapter = new ContentAssistCommandAdapter( organizationText, new TextContentAdapter(), new OrganizationProvider(this), ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, null, true); contentProposalAdapter.setAutoActivationCharacters(null); contentProposalAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE); contentProposalAdapter.setFilterStyle(ContentProposalAdapter.FILTER_NONE); contentProposalAdapter.setAutoActivationDelay(100); contentProposalAdapter.addContentProposalListener(new IContentProposalListener2() { @Override public void proposalPopupOpened(ContentProposalAdapter adapter) { // Nothing } @Override public void proposalPopupClosed(ContentProposalAdapter adapter) { dialogChanged(); } }); } private void createPasswordField(final ScrolledForm form) { Label labelPassword = new Label(form.getBody(), SWT.NULL); labelPassword.setText(Messages.ServerLocationWizardPage_label_password); serverPasswordText = new Text(form.getBody(), SWT.BORDER | SWT.SINGLE | SWT.PASSWORD); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; serverPasswordText.setLayoutData(gd); if (edit && server.hasAuth()) { String previousPassword; try { previousPassword = ServersManager.getPassword(server); if (previousPassword != null) { serverPasswordText.setText(previousPassword); } } catch (StorageException e) { SonarLintLogger.get().error(ERROR_READING_SECURE_STORAGE, e); MessageDialog.openError(this.getShell(), ERROR_READING_SECURE_STORAGE, "Unable to read password from secure storage: " + e.getMessage()); } } } private void createUsernameField(Composite parent, final ScrolledForm form) { Label labelUsername = new Label(form.getBody(), SWT.NULL); labelUsername.setText(Messages.ServerLocationWizardPage_label_username); serverUsernameText = new Text(form.getBody(), SWT.BORDER | SWT.SINGLE); serverUsernameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); if (edit && server.hasAuth()) { String previousUsername; try { previousUsername = ServersManager.getUsername(server); if (previousUsername != null) { serverUsernameText.setText(previousUsername); } } catch (StorageException e) { SonarLintLogger.get().error(ERROR_READING_SECURE_STORAGE, e); MessageDialog.openError(parent.getDisplay().getActiveShell(), ERROR_READING_SECURE_STORAGE, "Unable to read username from secure storage: " + e.getMessage()); } } } private void createServerUrlField(final ScrolledForm form) { Label labelUrl = new Label(form.getBody(), SWT.NULL); labelUrl.setText(Messages.ServerLocationWizardPage_label_host); serverUrlText = new Text(form.getBody(), SWT.BORDER | SWT.SINGLE); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; serverUrlText.setLayoutData(gd); if (edit) { serverUrlText.setText(StringUtils.defaultString(server.getHost())); } else { serverUrlText.setText(DEFAULT_URL_SUGGESTION); } serverUrlText.setFocus(); serverUrlText.setSelection(serverUrlText.getText().length()); serverUrlText.addModifyListener(e -> suggestServerId()); } private void suggestServerId() { if (!edit && !serverIdManuallyChanged) { try { URL url = new URL(serverUrlText.getText()); String organization = organizationText.getText(); String suggestedId = url.getHost(); if (StringUtils.isNotBlank(organization)) { suggestedId += "/" + organization; } serverIdText.removeModifyListener(idModifyListener); serverIdText.setText(suggestedId); serverIdText.addModifyListener(idModifyListener); } catch (MalformedURLException e1) { // Ignore } } dialogChanged(); } private void createServerIdField(final ScrolledForm form) { boolean isEditable = !edit; Label labelId = new Label(form.getBody(), SWT.NULL); labelId.setText(Messages.ServerLocationWizardPage_label_id); serverIdText = new Text(form.getBody(), isEditable ? (SWT.BORDER | SWT.SINGLE) : (SWT.BORDER | SWT.READ_ONLY)); GridData gdId = new GridData(GridData.FILL_HORIZONTAL); gdId.horizontalSpan = 2; serverIdText.setLayoutData(gdId); serverIdText.setEnabled(isEditable); serverIdText.setEditable(isEditable); if (edit) { serverIdText.setText(StringUtils.defaultString(server.getId())); } else { if (defaultServerId != null) { serverIdText.setText(defaultServerId); serverIdManuallyChanged = true; } else { serverIdManuallyChanged = false; } } idModifyListener = e -> { serverIdManuallyChanged = true; dialogChanged(); }; serverIdText.addModifyListener(idModifyListener); } private void createTestConnectionButton(Composite container) { Button testConnectionButton = new Button(container, SWT.PUSH); testConnectionButton.setText(Messages.ServerLocationWizardPage_action_test); testConnectionButton.setToolTipText(Messages.ServerLocationWizardPage_action_test_tooltip); GridData gd = new GridData(); gd.horizontalSpan = 3; gd.horizontalAlignment = GridData.CENTER; testConnectionButton.setLayoutData(gd); testConnectionButton.addListener(SWT.Selection, e -> { try { ServerConnectionTestJob testJob = new ServerConnectionTestJob(transcientServer(), getUsername(), getPassword()); getWizard().getContainer().run(true, true, testJob); status = testJob.getStatus(); } catch (OperationCanceledException e1) { status = Status.CANCEL_STATUS; } catch (Exception e1) { status = new Status(IStatus.ERROR, SonarLintUiPlugin.PLUGIN_ID, Messages.ServerLocationWizardPage_msg_error + " " + e1.getMessage(), e1); } getWizard().getContainer().updateButtons(); String message = status.getMessage(); if (status.getSeverity() == IStatus.OK) { setMessage(message, IMessageProvider.INFORMATION); } else { setMessage(message, IMessageProvider.ERROR); } }); } private void createOpenSecurityPageButton(Composite container) { Button button = new Button(container, SWT.PUSH); button.setText(Messages.ServerLocationWizardPage_action_token); button.setToolTipText(Messages.ServerLocationWizardPage_action_token_tooltip); button.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); button.addListener(SWT.Selection, e -> generateToken()); } private void generateToken() { if (StringUtils.isBlank(getServerUrl())) { MessageDialog.openError(this.getShell(), "Invalid Server URL", "Please fill the 'Server Url' field"); return; } StringBuilder url = new StringBuilder(256); url.append(getServerUrl()); url.append("/account/security"); try { PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(new URL(url.toString())); } catch (PartInitException | MalformedURLException e) { SonarLintLogger.get().error("Unable to open external browser", e); MessageDialog.openError(this.getShell(), "Error", "Unable to open external browser: " + e.getMessage()); } } private void dialogChanged() { updateStatus(SonarLintCorePlugin.getServersManager().validate(getServerId(), getServerUrl(), edit)); } private void updateStatus(String message) { setErrorMessage(message); setPageComplete(message == null); } public String getServerId() { return serverIdText.getText(); } public String getServerUrl() { return StringUtils.removeEnd(serverUrlText.getText(), "/"); } public String getOrganization() { return organizationText.getText(); } public String getUsername() { return serverUsernameText.getText(); } public String getPassword() { return serverPasswordText.getText(); } IServer transcientServer() { return SonarLintCorePlugin.getServersManager().create(getServerId(), getServerUrl(), StringUtils.trimToNull(getOrganization()), getUsername(), getPassword()); } }