| /* |
| * Copyright (c) 2015 Eike Stepper (Berlin, Germany) and others. |
| * All rights reserved. This program and the accompanying materials |
| * are 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 |
| * |
| * Contributors: |
| * Eike Stepper - initial API and implementation |
| */ |
| package org.eclipse.emf.cdo.explorer.ui.repositories.wizards; |
| |
| import org.eclipse.emf.cdo.admin.CDOAdminClient; |
| import org.eclipse.emf.cdo.admin.CDOAdminClientManager; |
| import org.eclipse.emf.cdo.admin.CDOAdminClientRepository; |
| import org.eclipse.emf.cdo.admin.CDOAdminClientUtil; |
| import org.eclipse.emf.cdo.explorer.repositories.CDORepository.IDGeneration; |
| import org.eclipse.emf.cdo.explorer.repositories.CDORepository.VersioningMode; |
| import org.eclipse.emf.cdo.explorer.ui.ViewerUtil; |
| import org.eclipse.emf.cdo.explorer.ui.bundle.OM; |
| import org.eclipse.emf.cdo.net4j.CDONet4jSession; |
| import org.eclipse.emf.cdo.net4j.CDONet4jSessionConfiguration; |
| import org.eclipse.emf.cdo.net4j.CDONet4jUtil; |
| import org.eclipse.emf.cdo.session.CDORepositoryInfo; |
| |
| import org.eclipse.net4j.Net4jUtil; |
| import org.eclipse.net4j.connector.IConnector; |
| import org.eclipse.net4j.util.container.ContainerEventAdapter; |
| import org.eclipse.net4j.util.container.ContainerUtil; |
| import org.eclipse.net4j.util.container.IContainer; |
| import org.eclipse.net4j.util.container.IManagedContainer; |
| import org.eclipse.net4j.util.event.IEvent; |
| import org.eclipse.net4j.util.event.IListener; |
| import org.eclipse.net4j.util.lifecycle.LifecycleUtil; |
| import org.eclipse.net4j.util.security.IPasswordCredentials; |
| import org.eclipse.net4j.util.security.IPasswordCredentialsProvider; |
| import org.eclipse.net4j.util.security.NotAuthenticatedException; |
| import org.eclipse.net4j.util.security.PasswordCredentialsProvider; |
| import org.eclipse.net4j.util.ui.views.ContainerItemProvider; |
| |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.IStructuredContentProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.LabelProvider; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.TableViewer; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.ui.ISharedImages; |
| import org.eclipse.ui.PlatformUI; |
| |
| import java.net.InetAddress; |
| import java.net.InetSocketAddress; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public class MasterRepositoryController |
| { |
| private static final Image REPOSITORY_IMAGE = OM.getImage("icons/repository.gif"); |
| |
| private static final Image EMPTY_IMAGE = OM.getImage("icons/empty.gif"); |
| |
| private static final Image OK_IMAGE = OM.getImage("icons/ok.gif"); |
| |
| private static final Image ERROR_IMAGE = PlatformUI.getWorkbench().getSharedImages() |
| .getImage(ISharedImages.IMG_OBJS_ERROR_TSK); |
| |
| private static final int VALIDATING_WIDTH = 120; |
| |
| private final DisposeListener disposeListener = new DisposeListener() |
| { |
| public void widgetDisposed(DisposeEvent e) |
| { |
| dispose(); |
| } |
| }; |
| |
| private IListener adminListener = new IListener() |
| { |
| public void notifyEvent(IEvent event) |
| { |
| ViewerUtil.refresh(repositoryTableViewer, null); |
| } |
| }; |
| |
| private IListener adminManagerListener = new ContainerEventAdapter<CDOAdminClient>() |
| { |
| @Override |
| protected void onAdded(IContainer<CDOAdminClient> container, CDOAdminClient admin) |
| { |
| admin.addListener(adminListener); |
| } |
| |
| @Override |
| protected void onRemoved(IContainer<CDOAdminClient> container, CDOAdminClient admin) |
| { |
| admin.removeListener(adminListener); |
| } |
| }; |
| |
| private CDOAdminClientManager adminManager; |
| |
| private IManagedContainer container; |
| |
| private Composite parent; |
| |
| private Text hostText; |
| |
| private ValidatingText portText; |
| |
| private TableViewer repositoryTableViewer; |
| |
| private ValidatingText repositoryNameText; |
| |
| private Label userNameLabel; |
| |
| private Text userNameText; |
| |
| private Label passwordLabel; |
| |
| private Text passwordText; |
| |
| private String connectorDescription; |
| |
| private String repositoryName; |
| |
| private String userName; |
| |
| private String password; |
| |
| private VersioningMode versioningMode; |
| |
| private IDGeneration idGeneration; |
| |
| public MasterRepositoryController(Composite parent) |
| { |
| this.parent = parent; |
| |
| container = ContainerUtil.createPluginContainer(); |
| LifecycleUtil.activate(container); |
| |
| adminManager = CDOAdminClientUtil.createAdminManager(container); |
| adminManager.addListener(adminManagerListener); |
| LifecycleUtil.activate(adminManager); |
| |
| AbstractRepositoryPage.createLabel(parent, "Host:"); |
| hostText = new Text(parent, SWT.BORDER); |
| hostText.setText("localhost"); |
| hostText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); |
| |
| AbstractRepositoryPage.createLabel(parent, "Port:"); |
| portText = new HostValidatingText(parent); |
| portText.setText("2036"); |
| hostText.addModifyListener(portText); |
| |
| AbstractRepositoryPage.createLabel(parent, "Repositories:"); |
| repositoryTableViewer = new TableViewer(parent, SWT.BORDER | SWT.SINGLE); |
| repositoryTableViewer.setContentProvider(new AdminContentProvider()); |
| repositoryTableViewer.setLabelProvider(new AdminLabelProvider()); |
| repositoryTableViewer.setInput(adminManager); |
| repositoryTableViewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
| repositoryTableViewer.addSelectionChangedListener(new ISelectionChangedListener() |
| { |
| public void selectionChanged(SelectionChangedEvent event) |
| { |
| IStructuredSelection selection = (IStructuredSelection)event.getSelection(); |
| CDOAdminClientRepository adminRepository = (CDOAdminClientRepository)selection.getFirstElement(); |
| if (adminRepository != null) |
| { |
| repositoryNameText.setText(adminRepository.getName()); |
| repositoryNameText.modifyText(false); |
| } |
| } |
| }); |
| |
| AbstractRepositoryPage.createLabel(parent, "Repository name:"); |
| repositoryNameText = new RepositoryValidatingText(parent); |
| |
| userNameLabel = AbstractRepositoryPage.createLabel(parent, "User name:"); |
| userNameText = new Text(parent, SWT.BORDER); |
| userNameText.setLayoutData(createWidthGridData()); |
| userNameText.addModifyListener(new ModifyListener() |
| { |
| public void modifyText(ModifyEvent e) |
| { |
| userName = userNameText.getText(); |
| repositoryNameText.modifyText(true); |
| } |
| }); |
| |
| passwordLabel = AbstractRepositoryPage.createLabel(parent, "Password:"); |
| passwordText = new Text(parent, SWT.BORDER | SWT.PASSWORD); |
| passwordText.setLayoutData(createWidthGridData()); |
| passwordText.addModifyListener(new ModifyListener() |
| { |
| public void modifyText(ModifyEvent e) |
| { |
| password = passwordText.getText(); |
| repositoryNameText.modifyText(true); |
| } |
| }); |
| |
| portText.modifyText(false); |
| repositoryNameText.modifyText(false); |
| |
| parent.addDisposeListener(disposeListener); |
| } |
| |
| public final String getConnectorDescription() |
| { |
| return connectorDescription; |
| } |
| |
| public final String getRepositoryName() |
| { |
| return repositoryName; |
| } |
| |
| public final String getUserName() |
| { |
| return userName; |
| } |
| |
| public final String getPassword() |
| { |
| return password; |
| } |
| |
| public final VersioningMode getVersioningMode() |
| { |
| return versioningMode; |
| } |
| |
| public final IDGeneration getIDGeneration() |
| { |
| return idGeneration; |
| } |
| |
| public final boolean isValid() |
| { |
| return portText.isValid() && repositoryNameText.isValid(); |
| } |
| |
| public void dispose() |
| { |
| parent.removeDisposeListener(disposeListener); |
| |
| if (container != null) |
| { |
| repositoryNameText.cancelValidation(); |
| portText.cancelValidation(); |
| |
| LifecycleUtil.deactivate(adminManager); |
| adminManager = null; |
| |
| container.deactivate(); |
| container = null; |
| } |
| } |
| |
| protected void validateController() |
| { |
| if (repositoryNameText != null) |
| { |
| repositoryName = repositoryNameText.getText(); |
| } |
| } |
| |
| protected void showCredentials(final boolean show) |
| { |
| parent.getDisplay().asyncExec(new Runnable() |
| { |
| public void run() |
| { |
| if (!parent.isDisposed()) |
| { |
| userNameLabel.setEnabled(show); |
| userNameText.setEnabled(show); |
| passwordLabel.setEnabled(show); |
| passwordText.setEnabled(show); |
| } |
| } |
| }); |
| } |
| |
| private static GridData createWidthGridData() |
| { |
| GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false); |
| gridData.widthHint = VALIDATING_WIDTH; |
| return gridData; |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private abstract class ValidatingText extends Composite implements ModifyListener |
| { |
| private Text text; |
| |
| private Label imageLabel; |
| |
| private Label statusLabel; |
| |
| private boolean valid; |
| |
| private ValidationThread validationThread; |
| |
| public ValidatingText(Composite parent) |
| { |
| super(parent, SWT.NONE); |
| setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); |
| |
| GridLayout layout = new GridLayout(3, false); |
| layout.marginWidth = 0; |
| layout.marginHeight = 0; |
| setLayout(layout); |
| |
| text = new Text(this, SWT.BORDER); |
| text.setLayoutData(createWidthGridData()); |
| text.addModifyListener(this); |
| |
| imageLabel = new Label(this, SWT.NONE); |
| |
| statusLabel = new Label(this, SWT.NONE); |
| statusLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); |
| } |
| |
| public final String getText() |
| { |
| return text.getText(); |
| } |
| |
| public final void setText(String text) |
| { |
| this.text.setText(text); |
| } |
| |
| public final boolean isValid() |
| { |
| return valid; |
| } |
| |
| public void cancelValidation() |
| { |
| if (validationThread != null) |
| { |
| validationThread.cancel(); |
| validationThread = null; |
| } |
| } |
| |
| public void modifyText(ModifyEvent e) |
| { |
| modifyText(true); |
| } |
| |
| public void modifyText(boolean delay) |
| { |
| validateController(); |
| |
| imageLabel.setImage(EMPTY_IMAGE); |
| statusLabel.setText(""); |
| |
| cancelValidation(); |
| |
| parent.getDisplay().timerExec(delay ? 400 : 0, new Runnable() |
| { |
| public void run() |
| { |
| if (!parent.isDisposed()) |
| { |
| String validationInfo = getValidationInfo(); |
| if (validationInfo != null) |
| { |
| validationThread = new ValidationThread(validationInfo); |
| validationThread.start(); |
| } |
| else |
| { |
| finished(false); |
| } |
| } |
| } |
| }); |
| } |
| |
| protected abstract String getValidationInfo(); |
| |
| protected abstract String validate(String validationInfo) throws Exception; |
| |
| protected void finished(boolean valid) |
| { |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class ValidationThread extends Thread |
| { |
| private final String validationInfo; |
| |
| private boolean canceled; |
| |
| public ValidationThread(String validationInfo) |
| { |
| super("Host Validator"); |
| setDaemon(true); |
| |
| this.validationInfo = validationInfo; |
| } |
| |
| public void cancel() |
| { |
| canceled = true; |
| interrupt(); |
| } |
| |
| @Override |
| public void run() |
| { |
| updateLabels(null, false); |
| String message = null; |
| valid = false; |
| |
| try |
| { |
| message = validate(validationInfo); |
| |
| if (!canceled) |
| { |
| valid = true; |
| } |
| } |
| catch (Exception ex) |
| { |
| message = ex.getMessage(); |
| } |
| |
| if (canceled) |
| { |
| return; |
| } |
| |
| updateLabels(message, valid); |
| } |
| |
| private void updateLabels(final String message, final boolean valid) |
| { |
| Display display = parent.getDisplay(); |
| if (!parent.isDisposed()) |
| { |
| display.syncExec(new Runnable() |
| { |
| public void run() |
| { |
| try |
| { |
| if (message != null) |
| { |
| imageLabel.setImage(valid ? OK_IMAGE : ERROR_IMAGE); |
| statusLabel.setText(message); |
| finished(valid); |
| } |
| } |
| catch (Exception ex) |
| { |
| //$FALL-THROUGH$ |
| } |
| |
| validateController(); |
| } |
| }); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class HostValidatingText extends ValidatingText |
| { |
| public HostValidatingText(Composite parent) |
| { |
| super(parent); |
| } |
| |
| @Override |
| protected String getValidationInfo() |
| { |
| connectorDescription = null; |
| |
| String host = hostText.getText(); |
| if (host.length() == 0) |
| { |
| return null; |
| } |
| |
| String port = getText(); |
| if (port.length() == 0) |
| { |
| port = "2036"; |
| } |
| |
| return host + ":" + port; |
| } |
| |
| @Override |
| protected String validate(String validationInfo) throws Exception |
| { |
| String[] tokens = validationInfo.split(":"); |
| String host = tokens[0]; |
| String port = tokens[1]; |
| |
| InetAddress addr; |
| |
| try |
| { |
| addr = InetAddress.getByName(host); |
| } |
| catch (Exception ex) |
| { |
| throw new Exception("Unknown host"); |
| } |
| |
| try |
| { |
| new InetSocketAddress(addr, Integer.parseInt(port)); |
| } |
| catch (IllegalArgumentException ex) |
| { |
| throw new Exception("Invalid port"); |
| } |
| |
| connectorDescription = validationInfo; |
| return "Valid address"; |
| } |
| |
| @Override |
| protected void finished(boolean valid) |
| { |
| repositoryNameText.modifyText(false); |
| |
| if (valid && connectorDescription != null) |
| { |
| adminManager.addConnection("tcp://" + connectorDescription); |
| } |
| |
| ViewerUtil.refresh(repositoryTableViewer, null); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class RepositoryValidatingText extends ValidatingText |
| { |
| private boolean authenticating; |
| |
| public RepositoryValidatingText(Composite parent) |
| { |
| super(parent); |
| } |
| |
| @Override |
| protected String getValidationInfo() |
| { |
| if (connectorDescription == null) |
| { |
| return null; |
| } |
| |
| String repositoryName = getText(); |
| if (repositoryName.length() == 0) |
| { |
| return null; |
| } |
| |
| return repositoryName; |
| } |
| |
| @Override |
| protected String validate(String repositoryName) throws Exception |
| { |
| CDONet4jSession session = null; |
| authenticating = false; |
| |
| versioningMode = null; |
| idGeneration = null; |
| |
| try |
| { |
| IConnector connector = getConnector(); |
| IPasswordCredentialsProvider credentialsProvider = new PasswordCredentialsProvider(userName, password) |
| { |
| @Override |
| public IPasswordCredentials getCredentials() |
| { |
| authenticating = true; |
| return super.getCredentials(); |
| } |
| }; |
| |
| try |
| { |
| CDONet4jSessionConfiguration config = CDONet4jUtil.createNet4jSessionConfiguration(); |
| config.setConnector(connector); |
| config.setRepositoryName(repositoryName); |
| config.setCredentialsProvider(credentialsProvider); |
| |
| session = config.openNet4jSession(); |
| if (session != null && session.isClosed()) |
| { |
| session = null; |
| } |
| } |
| catch (NotAuthenticatedException ex) |
| { |
| authenticating = true; |
| } |
| catch (Exception ex) |
| { |
| session = null; |
| } |
| |
| if (session == null) |
| { |
| showCredentials(true); |
| if (authenticating) |
| { |
| throw new Exception("Authentication failed"); |
| } |
| |
| throw new Exception("Repository unreachable"); |
| } |
| |
| showCredentials(authenticating); |
| |
| CDORepositoryInfo repositoryInfo = session.getRepositoryInfo(); |
| versioningMode = VersioningMode.from(repositoryInfo); |
| idGeneration = IDGeneration.from(repositoryInfo); |
| |
| String message = versioningMode.toString(); |
| if (versioningMode == VersioningMode.Branching && idGeneration == IDGeneration.UUID) |
| { |
| message += ", Replicable"; |
| } |
| |
| return message; |
| } |
| finally |
| { |
| LifecycleUtil.deactivate(session); |
| } |
| } |
| |
| private IConnector getConnector() throws Exception |
| { |
| IConnector connector = null; |
| |
| try |
| { |
| connector = Net4jUtil.getConnector(container, "tcp", connectorDescription); |
| } |
| catch (Exception ex) |
| { |
| connector = null; |
| } |
| |
| if (connector == null) |
| { |
| throw new Exception("Host unreachable"); |
| } |
| |
| return connector; |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class AdminContentProvider implements IStructuredContentProvider |
| { |
| public void inputChanged(Viewer viewer, Object oldInput, Object newInput) |
| { |
| } |
| |
| public void dispose() |
| { |
| } |
| |
| public Object[] getElements(Object inputElement) |
| { |
| if (connectorDescription != null) |
| { |
| for (CDOAdminClient admin : adminManager.getConnections()) |
| { |
| String url = admin.getURL(); |
| if (url.equals("tcp://" + connectorDescription)) |
| { |
| return admin.getRepositories(); |
| } |
| } |
| } |
| |
| return ContainerItemProvider.NO_ELEMENTS; |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class AdminLabelProvider extends LabelProvider |
| { |
| @Override |
| public Image getImage(Object element) |
| { |
| if (element instanceof CDOAdminClientRepository) |
| { |
| return REPOSITORY_IMAGE; |
| } |
| |
| return super.getImage(element); |
| } |
| |
| @Override |
| public String getText(Object element) |
| { |
| if (element instanceof CDOAdminClientRepository) |
| { |
| CDOAdminClientRepository adminRepository = (CDOAdminClientRepository)element; |
| return adminRepository.getName(); |
| } |
| |
| return super.getText(element); |
| } |
| } |
| } |