/*******************************************************************************
* Copyright (c) 2015-2016 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
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.openshift.internal.ui.wizard.deployimage;
import java.util.List;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Text;
import org.jboss.tools.common.ui.databinding.ValueBindingBuilder;
import org.jboss.tools.openshift.internal.common.ui.databinding.RequiredControlDecorationUpdater;
import org.jboss.tools.openshift.internal.common.ui.wizard.AbstractOpenShiftWizardPage;
import org.jboss.tools.openshift.internal.common.ui.wizard.OkCancelButtonWizardDialog;
import com.openshift.restclient.model.IServicePort;
/**
* Dialog to configure the port mapping for a Docker Image to be deployed.
*/
public class ServicePortDialog extends AbstractOpenShiftWizardPage {
static final String UNIQUE_ERROR = "The {0} port number must be unique among all the other ports exposed by this OpenShift service.";
static final String PROPERTY_SERVICE_PORT = "port";
static final String PROPERTY_POD_PORT = "targetPort";
private final ServicePortAdapter model;
private final List<IServicePort> ports;
/**
* Constructor
* @param model
* @param message
* @param ports
*/
public ServicePortDialog(final ServicePortAdapter model, final String message, final List<IServicePort> ports) {
super("Configure Service Ports", message, "", null);
this.model = model;
this.ports = ports;
}
@Override
protected void doCreateControls(final Composite parent, final DataBindingContext dbc) {
GridLayoutFactory.fillDefaults()
.margins(1, 1).applyTo(parent);
final Composite dialogArea = new Composite(parent, SWT.NONE);
GridDataFactory.fillDefaults()
.align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(dialogArea);
GridLayoutFactory.fillDefaults()
.numColumns(2)
.applyTo(dialogArea);
//service port
final Label servicePortLabel = new Label(dialogArea, SWT.NONE);
servicePortLabel.setText("Service port:");
GridDataFactory.fillDefaults()
.align(SWT.LEFT, SWT.CENTER)
.applyTo(servicePortLabel);
final Spinner servicePortSpinner = new Spinner(dialogArea, SWT.BORDER);
servicePortSpinner.setMinimum(1);
servicePortSpinner.setMaximum(65535);
servicePortSpinner.setToolTipText("The port exposed by the service that will route to the pod.");
servicePortSpinner.addModifyListener(e -> {
Spinner source = (Spinner) e.getSource();
if (!String.valueOf(source.getSelection()).equals(source.getText())) {
source.setSelection(source.getSelection());
}
});
GridDataFactory.fillDefaults()
.align(SWT.FILL, SWT.CENTER)
.applyTo(servicePortSpinner);
final Binding servicePortBinding = ValueBindingBuilder
.bind(WidgetProperties.selection().observe(servicePortSpinner))
.validatingAfterConvert(new ServicePortValidator(model.getPort(), this.ports))
.to(BeanProperties.value(PROPERTY_SERVICE_PORT).observe(model))
.in(dbc);
ControlDecorationSupport.create(
servicePortBinding, SWT.LEFT | SWT.TOP, null, new RequiredControlDecorationUpdater());
// Pod port
final Label podPortLabel = new Label(dialogArea, SWT.NONE);
podPortLabel.setText("Pod port:");
GridDataFactory.fillDefaults()
.align(SWT.LEFT, SWT.CENTER).applyTo(podPortLabel);
final Text podPortText = new Text(dialogArea, SWT.BORDER);
podPortText.setToolTipText("The port exposed by the pod which will accept traffic.\nIt must be an integer or the name of a port in the backend Pods.");
GridDataFactory.fillDefaults()
.align(SWT.FILL, SWT.CENTER)
.grab(true, false)
.applyTo(podPortText);
final Binding podPortBinding = ValueBindingBuilder
.bind(WidgetProperties.text(SWT.Modify).observe(podPortText))
.validatingAfterConvert(new PodPortValidator(this.model.getTargetPort(), this.ports))
.to(BeanProperties.value(PROPERTY_POD_PORT).observe(model))
.in(dbc);
ControlDecorationSupport.create(
podPortBinding, SWT.LEFT | SWT.TOP, null, new RequiredControlDecorationUpdater());
final Button routePortButton = new Button(dialogArea, SWT.CHECK);
routePortButton.setText("Used by route");
GridDataFactory.fillDefaults()
.align(SWT.FILL, SWT.CENTER)
.grab(true, false)
.span(2, 1)
.applyTo(routePortButton);
ValueBindingBuilder
.bind(WidgetProperties.selection().observe(routePortButton))
.to(BeanProperties.value(ServicePortAdapter.ROUTE_PORT).observe(model))
.in(dbc);
}
/**
* Validates the Service Port
*/
static class ServicePortValidator implements IValidator{
private static final IStatus SERVICE_PORT_ERROR = ValidationStatus.error(NLS.bind(UNIQUE_ERROR, "service"));
private final int servicePort;
private final List<? extends IServicePort> ports;
public ServicePortValidator(final int servicePort, final List<? extends IServicePort> ports) {
this.servicePort = servicePort;
this.ports = ports;
}
@Override
public IStatus validate(Object value) {
Integer newPort = (Integer) value;
if(servicePort != newPort) {
for (IServicePort port : ports) {
if(newPort.intValue() == port.getPort()) {
return SERVICE_PORT_ERROR;
}
}
}
return ValidationStatus.OK_STATUS;
}
}
/**
* Opens this dialog.
*
* @return the return code, ie, the value of the button that the user
* clicked to close the dialog.
*/
public int open() {
final IWizardPage page = this;
Wizard wizard = new Wizard() {
@Override
public boolean performFinish() {
return true;
}
@Override
public void addPages() {
addPage(page);
}
};
wizard.setNeedsProgressMonitor(true);
wizard.setWindowTitle("Service Ports");
this.setWizard(wizard);
OkCancelButtonWizardDialog dialog =
new OkCancelButtonWizardDialog(getShell(), wizard);
return dialog.open();
}
}