/******************************************************************************* * Copyright (c) 2015, 2016 Red Hat Inc. 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: * Red Hat - Initial Contribution *******************************************************************************/ package org.eclipse.linuxtools.internal.docker.ui.launch; import static org.eclipse.linuxtools.internal.docker.ui.launch.IRunDockerImageLaunchConfigurationConstants.MEMORY_LIMIT; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import org.eclipse.core.databinding.Binding; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.UpdateValueStrategy; import org.eclipse.core.databinding.beans.BeanProperties; import org.eclipse.core.databinding.observable.IChangeListener; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; import org.eclipse.jface.databinding.swt.WidgetProperties; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.linuxtools.docker.ui.Activator; import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunResourceVolumesVariablesModel; import org.eclipse.linuxtools.internal.docker.ui.wizards.WizardMessages; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Scale; import org.eclipse.swt.widgets.Text; public class RunImageResourcesTab extends AbstractLaunchConfigurationTab { private static final String TAB_NAME = "RunResourcesTab.name"; //$NON-NLS-1$ private static final int COLUMNS = 2; private final DataBindingContext dbc = new DataBindingContext(); private ImageRunResourceVolumesVariablesModel model = null; private Composite container; public RunImageResourcesTab(ImageRunResourceVolumesVariablesModel model) { this.model = model; } @Override public void createControl(Composite parent) { final Composite container = new Composite(parent, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(1, 1) .grab(true, false).applyTo(container); GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(6, 6) .applyTo(container); if (model == null) { setErrorMessage(LaunchMessages.getString("NoConnectionError.msg")); } else { setErrorMessage(null); createResourceSettingsContainer(container); } setControl(container); } private void createResourceSettingsContainer(final Composite parent) { final Composite container = new Composite(parent, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL) .span(COLUMNS, 1).grab(true, false).applyTo(container); GridLayoutFactory.fillDefaults().spacing(10, 2).applyTo(container); final Button enableResourceLimitationButton = new Button(container, SWT.CHECK); enableResourceLimitationButton.setText(WizardMessages.getString( "ImageRunResourceVolVarPage.enableLimitationButton")); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .applyTo(enableResourceLimitationButton); dbc.bindValue( WidgetProperties.selection() .observe(enableResourceLimitationButton), BeanProperties .value(ImageRunResourceVolumesVariablesModel.class, ImageRunResourceVolumesVariablesModel.ENABLE_RESOURCE_LIMITATIONS) .observe(model)); final int COLUMNS = 5; final int INDENT = 20; final Composite subContainer = new Composite(container, SWT.NONE); setContainer(subContainer); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL) .indent(INDENT, 0).span(COLUMNS, 1).grab(true, false) .applyTo(subContainer); GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(6, 6) .spacing(10, 2).applyTo(subContainer); // specify CPU limitation final Label cpuPriorityLabel = new Label(subContainer, SWT.NONE); cpuPriorityLabel.setText(WizardMessages .getString("ImageRunResourceVolVarPage.cpuPriorityLabel")); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).applyTo(cpuPriorityLabel); final Button lowCPULimitationButton = new Button(subContainer, SWT.RADIO); lowCPULimitationButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.lowButton")); //$NON-NLS-1$ bindButton(lowCPULimitationButton, ImageRunResourceVolumesVariablesModel.CPU_LOW); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .applyTo(lowCPULimitationButton); final Button mediumCPULimitationButton = new Button(subContainer, SWT.RADIO); mediumCPULimitationButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.mediumButton")); //$NON-NLS-1$ bindButton(mediumCPULimitationButton, ImageRunResourceVolumesVariablesModel.CPU_MEDIUM); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .applyTo(mediumCPULimitationButton); final Button highCPULimitationButton = new Button(subContainer, SWT.RADIO); highCPULimitationButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.highButton")); //$NON-NLS-1$ bindButton(highCPULimitationButton, ImageRunResourceVolumesVariablesModel.CPU_HIGH); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1) .applyTo(highCPULimitationButton); // Memory limitation final Label memoryLimitLabel = new Label(subContainer, SWT.NONE); memoryLimitLabel.setText(WizardMessages .getString("ImageRunResourceVolVarPage.memoryLimit")); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).applyTo(memoryLimitLabel); final Scale memoryLimitSpinner = new Scale(subContainer, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).span(2, 1).applyTo(memoryLimitSpinner); memoryLimitSpinner.setBackground( Display.getDefault().getSystemColor(SWT.COLOR_TRANSPARENT)); memoryLimitSpinner.setMinimum(0); memoryLimitSpinner.setMaximum(this.model.getTotalMemory()); memoryLimitSpinner.setPageIncrement(64); dbc.bindValue(WidgetProperties.selection().observe(memoryLimitSpinner), BeanProperties .value(ImageRunResourceVolumesVariablesModel.class, ImageRunResourceVolumesVariablesModel.MEMORY_LIMIT) .observe(model)); final Text memoryLimitValueText = new Text(subContainer, SWT.BORDER); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).hint(50, SWT.DEFAULT) .applyTo(memoryLimitValueText); dbc.bindValue( WidgetProperties.text(SWT.Modify).observe(memoryLimitValueText), BeanProperties .value(ImageRunResourceVolumesVariablesModel.class, ImageRunResourceVolumesVariablesModel.MEMORY_LIMIT) .observe(model)); dbc.bindValue(WidgetProperties.selection().observe(memoryLimitSpinner), BeanProperties .value(ImageRunResourceVolumesVariablesModel.class, ImageRunResourceVolumesVariablesModel.MEMORY_LIMIT) .observe(model)); final Label memoryLimitValueLabel = new Label(subContainer, SWT.NONE); memoryLimitValueLabel.setText("MB"); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).applyTo(memoryLimitValueLabel); // enable/disable controls final IObservableValue enableResourceLimitationsObservable = BeanProperties .value(ImageRunResourceVolumesVariablesModel.class, ImageRunResourceVolumesVariablesModel.ENABLE_RESOURCE_LIMITATIONS) .observe(model); dbc.bindValue( WidgetProperties.selection() .observe(enableResourceLimitationButton), enableResourceLimitationsObservable); enableResourceLimitationsObservable .addChangeListener(onEnableResourceLimitation(subContainer)); toggleResourceLimitationControls(subContainer); } private void setContainer(final Composite container) { this.container = container; } private Composite getContainer() { return container; } /** * Binds the given <code>cpuShares</code> value to the given {@link Button} * when it is selected. * * @param button * the {@link Button} to bind * @param cpuShares * the <code>cpuShares</code> to bind to the {@link Button} * @return */ private Binding bindButton(final Button button, final long cpuShares) { return dbc.bindValue(WidgetProperties.selection().observe(button), BeanProperties .value(ImageRunResourceVolumesVariablesModel.class, ImageRunResourceVolumesVariablesModel.CPU_SHARE_WEIGHT) .observe(model), new UpdateValueStrategy() { @Override public Object convert(Object value) { if (value.equals(Boolean.TRUE)) { return cpuShares; } return 0l; } }, new UpdateValueStrategy() { @Override public Object convert(final Object value) { return value.equals(cpuShares); } }); } private IChangeListener onEnableResourceLimitation( final Composite container) { return event -> toggleResourceLimitationControls(container); } private void toggleResourceLimitationControls(Composite container) { for (Control childControl : container.getChildren()) { if (model.isEnableResourceLimitations()) { childControl.setEnabled(true); } else { childControl.setEnabled(false); } updateLaunchConfigurationDialog(); } } @Override public Image getImage() { return SWTImagesFactory.get(SWTImagesFactory.IMG_RESOURCE); } @Override public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { // TODO Auto-generated method stub } @Override public void initializeFrom(ILaunchConfiguration configuration) { if (model == null) return; try { boolean enableLimits = configuration.getAttribute( IRunDockerImageLaunchConfigurationConstants.ENABLE_LIMITS, false); model.setEnableResourceLimitations(enableLimits); long cpuShareWeight = Long.parseLong(configuration.getAttribute( IRunDockerImageLaunchConfigurationConstants.CPU_PRIORITY, Long.toString( ImageRunResourceVolumesVariablesModel.CPU_MEDIUM))); model.setCpuShareWeight(cpuShareWeight); int maxMemory = this.model.getTotalMemory(); // retrieve memory limit stored in MB final long memoryLimit = Long .parseLong(configuration.getAttribute(MEMORY_LIMIT, Long.toString( ImageRunResourceVolumesVariablesModel.DEFAULT_MEMORY))); // make sure memory limit is not higher than maxMemory model.setMemoryLimit(Math.min(maxMemory, memoryLimit)); toggleResourceLimitationControls(getContainer()); } catch (CoreException e) { Activator.logErrorMessage( LaunchMessages.getString( "RunDockerImageLaunchConfiguration.load.failure"), //$NON-NLS-1$ e); } model.addPropertyChangeListener( new LaunchConfigurationChangeListener()); } @Override public void performApply(ILaunchConfigurationWorkingCopy configuration) { if (model == null) return; configuration.setAttribute( IRunDockerImageLaunchConfigurationConstants.ENABLE_LIMITS, model.isEnableResourceLimitations()); configuration.setAttribute( IRunDockerImageLaunchConfigurationConstants.MEMORY_LIMIT, Long.toString(model.getMemoryLimit())); configuration.setAttribute( IRunDockerImageLaunchConfigurationConstants.CPU_PRIORITY, Long.toString(model.getCpuShareWeight())); } @Override public String getName() { return LaunchMessages.getString(TAB_NAME); } private class LaunchConfigurationChangeListener implements PropertyChangeListener { @Override public void propertyChange(final PropertyChangeEvent evt) { updateLaunchConfigurationDialog(); } } }