/* * � Copyright IBM Corp. 2015, 2016 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.ibm.xsp.extlib.designer.bluemix.manifest.editor; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.ArrayList; import java.util.List; import org.cloudfoundry.client.lib.CloudCredentials; import org.cloudfoundry.client.lib.CloudFoundryClient; import org.cloudfoundry.client.lib.domain.CloudService; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import com.ibm.commons.iloader.node.validators.IntegerValidator; import com.ibm.commons.swt.SWTLayoutUtils; import com.ibm.commons.swt.data.controls.DCCheckbox; import com.ibm.commons.swt.data.controls.DCComboBox; import com.ibm.commons.util.StringUtil; import com.ibm.xsp.extlib.designer.bluemix.config.BluemixConfig; import com.ibm.xsp.extlib.designer.bluemix.config.ConfigManager; import com.ibm.xsp.extlib.designer.bluemix.manifest.editor.ManifestTableEditor.CellEditorCallback; import com.ibm.xsp.extlib.designer.bluemix.manifest.editor.ManifestTableEditor.EditTableItem; import com.ibm.xsp.extlib.designer.bluemix.preference.PreferencePage; import com.ibm.xsp.extlib.designer.bluemix.util.BluemixUtil; import com.ibm.xsp.extlib.designer.xspprops.XSPEditorUtil; import static com.ibm.xsp.extlib.designer.bluemix.preference.PreferenceKeys.*; /** * @author Gary Marjoram * */ public class ManifestEditorPage extends AbstractManifestEditorPage implements CellEditorCallback { private ArrayList<EditTableItem> _serviceList; private ArrayList<CloudService> _cloudServices; private ArrayList<EditTableItem> _hostList; private ArrayList<EditTableItem> _domainList; private ManifestTableEditor _hostTableEditor; private ManifestTableEditor _domainTableEditor; private ManifestTableEditor _serviceTableEditor; private DCCheckbox _noRouteCheckbox; private List<Control> _routeControls; public ManifestEditorPage(Composite parent, FormToolkit toolkit, ManifestMultiPageEditor mpe) { super(parent, toolkit, mpe); } @Override protected void initialize() { _serviceList = new ArrayList<EditTableItem>(); _cloudServices = new ArrayList<CloudService>(); _hostList = new ArrayList<EditTableItem>(); _domainList = new ArrayList<EditTableItem>(); _routeControls = new ArrayList<Control>(); super.initialize(); } @Override protected String getPageTitle() { return BluemixUtil.productizeString("%BM_PRODUCT% Manifest"); // $NLX-ManifestEditorPage.BM_PRODUCTManifest-1$ } @Override protected void createLeftArea(Composite parent) { createStagingArea(parent); createServicesArea(parent); } @Override protected void createRightArea(Composite parent) { createRouteArea(parent); } private void createStagingArea(Composite parent) { Section section = XSPEditorUtil.createSection(_toolkit, parent, "Staging Settings", 1, 1); // $NLX-ManifestEditorPage.StagingSettings-1$ Composite container = XSPEditorUtil.createSectionChild(section, 3); // For de-indenting (MB) labels // Normal spacing is 20 so reduce to 5 GridData gd = new GridData(); gd.horizontalIndent = -15; Label tLabel = XSPEditorUtil.createLabel(container, "Application name:", 1); // $NLX-ManifestEditorPage.Applicationname-1$ tLabel.setToolTipText(BluemixUtil.productizeString("The %BM_PRODUCT% application name.")); // $NLX-ManifestEditorPage.TheIBMBluemixapplicationname-1$ XSPEditorUtil.createText(container, "appName", 2, 0, 2); // $NON-NLS-1$ tLabel = XSPEditorUtil.createLabel(container, "Instances:", 1); // $NLX-ManifestEditorPage.Instances-1$ tLabel.setToolTipText("Number of instances."); // $NLX-ManifestEditorPage.Numberofinstances-1$ XSPEditorUtil.createTextNoFill(container, "instances", 2, 0, 6).setValidator(IntegerValidator.positiveInstance); // $NON-NLS-1$ tLabel = XSPEditorUtil.createLabel(container, "Memory:", 1); // $NLX-ManifestEditorPage.Memory-1$ tLabel.setToolTipText("Memory for each instance."); // $NLX-ManifestEditorPage.Memoryforeachinstance-1$ XSPEditorUtil.createTextNoFill(container, "memory", 1, 0, 6).setValidator(IntegerValidator.positiveInstance); // $NON-NLS-1$ XSPEditorUtil.createLabel(container, "(MB)", 1).setLayoutData(gd); // $NON-NLS-1$ tLabel = XSPEditorUtil.createLabel(container, "Disk quota:", 1); // $NLX-ManifestEditorPage.Diskquota-1$ tLabel.setToolTipText("Disk quota for each instance."); // $NLX-ManifestEditorPage.Diskquotaforeachinstance-1$ XSPEditorUtil.createTextNoFill(container, "diskQuota", 1, 0, 6).setValidator(IntegerValidator.positiveInstance); // $NON-NLS-1$ XSPEditorUtil.createLabel(container, "(MB)", 1).setLayoutData(gd); // $NON-NLS-1$ tLabel = XSPEditorUtil.createLabel(container, "Build pack:", 1); // $NLX-ManifestEditorPage.Buildpack-1$ tLabel.setToolTipText("Build pack for the application."); // $NLX-ManifestEditorPage.Buildpackfortheapplication-1$ DCComboBox bpCombo = XSPEditorUtil.createDCCombo(container, "buildPack", 2, false, false); // $NON-NLS-1$ bpCombo.setLookup(new BasicLookup(new String[]{"xpages_buildpack"})); // $NON-NLS-1$ bpCombo.setEditableLabels(true); tLabel = XSPEditorUtil.createLabel(container, "Command:", 1); // $NLX-ManifestEditorPage.Command-1$ tLabel.setToolTipText("Launch command for the application."); // $NLX-ManifestEditorPage.Launchcommandfortheapplication-1$ DCComboBox cmdCombo = XSPEditorUtil.createDCCombo(container, "command", 2, false, false); // $NON-NLS-1$ cmdCombo.setLookup(new BasicLookup(new String[]{"/app/launch_xpages_webcontainer"})); // $NON-NLS-1$ bpCombo.setEditableLabels(true); tLabel = XSPEditorUtil.createLabel(container, "Timeout:", 1); // $NLX-ManifestEditorPage.Timeout-1$ tLabel.setToolTipText("Use the timeout attribute to give your application more time to start."); // $NLX-ManifestEditorPage.Usethetimeoutattributetogiveyoura-1$ XSPEditorUtil.createTextNoFill(container, "timeout", 1, 0, 6).setValidator(IntegerValidator.positiveInstance); // $NON-NLS-1$ XSPEditorUtil.createLabel(container, "(seconds)", 1).setLayoutData(gd); // $NLX-ManifestEditorPage.seconds-1$ tLabel = XSPEditorUtil.createLabel(container, "Path:", 1); // $NLX-ManifestEditorPage.Path-1$ tLabel.setToolTipText(BluemixUtil.productizeString("Use the path attribute to tell %BM_PRODUCT% where to find your application.")); // $NLX-ManifestEditorPage.UsethepathattributetotellIBMBluemixw-1$ XSPEditorUtil.createText(container, "path", 2, 0, 1); // $NON-NLS-1$ tLabel = XSPEditorUtil.createLabel(container, "Stack:", 1); // $NLX-ManifestEditorPage.Stack-1$ tLabel.setToolTipText("Use the stack attribute to specify an alternative root filesystem (rootfs) for your application."); // $NLX-ManifestEditorPage.Usethestackattributetospecifyanal-1$ XSPEditorUtil.createText(container, "stack", 2, 0, 1); // $NON-NLS-1$ section.setClient(container); } private void createRouteArea(Composite parent) { Section section = XSPEditorUtil.createSection(_toolkit, parent, "Route Settings", 1, 1); // $NLX-ManifestEditorPage.RouteSettings-1$ Composite container = XSPEditorUtil.createSectionChild(section, 2); _noRouteCheckbox = XSPEditorUtil.createCheckboxTF(container, "There is no route to this application", "noRoute", 2); // $NON-NLS-2$ $NLX-ManifestEditorPage.Thereisnoroutetothisapplication-1$ _noRouteCheckbox.setToolTipText("If set, there is no route to this application"); // $NLX-ManifestEditorPage.Ifsetthereisnoroutetothisapplicat-1$ _noRouteCheckbox.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { refreshRouteControlState(); } }); Label tLabel = XSPEditorUtil.createLabel(container, "Host:", 1); // $NLX-ManifestEditorPage.Host-1$ tLabel.setToolTipText("Use the host attribute to provide a hostname or subdomain. This segment of a route helps to ensure that the route is unique."); // $NLX-ManifestEditorPage.Usethehostattributetoprovideahost-1$ _routeControls.add(tLabel); _routeControls.add(XSPEditorUtil.createText(container, "host", 1, 0, 1)); // $NON-NLS-1$ tLabel = XSPEditorUtil.createLabel(container, "Hosts:", 1); // $NLX-ManifestEditorPage.Hosts-1$ tLabel.setToolTipText("Use the hosts attribute to provide multiple hostnames or subdomains. Each hostname generates a unique route for the app."); // $NLX-ManifestEditorPage.Usethehostsattributetoprovidemult-1$ ((GridData)tLabel.getLayoutData()).verticalAlignment = SWT.BEGINNING; ((GridData)tLabel.getLayoutData()).verticalIndent = 4; _routeControls.add(tLabel); _hostTableEditor = new ManifestTableEditor(container, 1, new String[]{"host"}, new String[]{""}, false, true, 4, 50, "bluemix.hosts", _hostList, true, this, null, null); // $NON-NLS-1$ $NON-NLS-2$ _routeControls.add(_hostTableEditor.getTable()); // Create the Buttons XSPEditorUtil.createLabel(container, "", 1); Composite btnContainer = new Composite(container, SWT.NONE); btnContainer.setLayout(SWTLayoutUtils.createLayoutNoMarginDefaultSpacing(2)); btnContainer.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); btnContainer.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); // Add Button Button addBtn = new Button(btnContainer, SWT.PUSH); addBtn.setText("Add"); // $NLX-ManifestEditorPage.Add-1$ addBtn.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { _hostTableEditor.createItem(new TableEntry("Host")); // $NLX-ManifestEditorPage.Host.2-1$ } }); _routeControls.add(addBtn); // Delete Button Button delBtn = new Button(btnContainer, SWT.PUSH); delBtn.setText("Delete"); // $NLX-ManifestEditorPage.Delete-1$ delBtn.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { _hostTableEditor.deleteItem(); } }); _routeControls.add(delBtn); tLabel = XSPEditorUtil.createLabel(container, "Domain:", 1); // $NLX-ManifestEditorPage.Domain-1$ tLabel.setToolTipText("Use the domain attribute when you want your application to be served from a domain other than the default shared domain."); // $NLX-ManifestEditorPage.Usethedomainattributewhenyouwanty-1$ _routeControls.add(tLabel); _routeControls.add(XSPEditorUtil.createText(container, "domain", 1, 0, 1)); // $NON-NLS-1$ tLabel = XSPEditorUtil.createLabel(container, "Domains:", 1); // $NLX-ManifestEditorPage.Domains-1$ tLabel.setToolTipText("Use the domains attribute to provide multiple domains."); // $NLX-ManifestEditorPage.Usethedomainsattributetoprovidemu-1$ _routeControls.add(tLabel); ((GridData)tLabel.getLayoutData()).verticalAlignment = SWT.BEGINNING; ((GridData)tLabel.getLayoutData()).verticalIndent = 4; _routeControls.add(addBtn); _domainTableEditor = new ManifestTableEditor(container, 1, new String[]{"domain"}, new String[]{""}, false, true, 4, 50, "bluemix.domains", _domainList, true, this, null, null); // $NON-NLS-1$ $NON-NLS-2$ _routeControls.add(_domainTableEditor.getTable()); // Create the Buttons XSPEditorUtil.createLabel(container, "", 1); btnContainer = new Composite(container, SWT.NONE); btnContainer.setLayout(SWTLayoutUtils.createLayoutNoMarginDefaultSpacing(2)); btnContainer.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); btnContainer.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); // Add Button addBtn = new Button(btnContainer, SWT.PUSH); addBtn.setText("Add"); // $NLX-ManifestEditorPage.Add-1$ addBtn.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { _domainTableEditor.createItem(new TableEntry("Domain")); // $NLX-ManifestEditorPage.Domain.2-1$ } }); _routeControls.add(addBtn); // Delete Button delBtn = new Button(btnContainer, SWT.PUSH); delBtn.setText("Delete"); // $NLX-ManifestEditorPage.Delete-1$ delBtn.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { _domainTableEditor.deleteItem(); } }); _routeControls.add(delBtn); section.setClient(container); } private void createServicesArea(Composite parent) { Section section = XSPEditorUtil.createSection(_toolkit, parent, "Bound Services", 1, 1); // $NLX-ManifestEditorPage.BoundServices-1$ Composite container = XSPEditorUtil.createSectionChild(section, 1); XSPEditorUtil.createLabel(container, "Specify the bound services for this application.", 1); // $NLX-ManifestEditorPage.Specifytheboundservicesforthisapp-1$ // Create the Table _serviceTableEditor = new ManifestTableEditor(container, 1, new String[]{"service"}, new String[]{"Service"}, true, true, 3, 60, "bluemix.services", _serviceList, true, this, null, null); // $NON-NLS-1$ $NON-NLS-3$ $NLX-ManifestEditorPage.Service-2$ // Create the Buttons Composite btnContainer = new Composite(container, SWT.NONE); btnContainer.setLayout(SWTLayoutUtils.createLayoutNoMarginDefaultSpacing(3)); btnContainer.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); btnContainer.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); // Add Button Button addBtn = new Button(btnContainer, SWT.PUSH); addBtn.setText("Add"); // $NLX-ManifestEditorPage.Add-1$ addBtn.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { _serviceTableEditor.createItem(new TableEntry("Service")); // $NLX-ManifestEditorPage.Service.1-1$ } }); // Delete Button Button delBtn = new Button(btnContainer, SWT.PUSH); delBtn.setText("Delete"); // $NLX-ManifestEditorPage.Delete-1$ delBtn.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { _serviceTableEditor.deleteItem(); } }); // Choose button Button chooseBtn = new Button(btnContainer, SWT.PUSH); chooseBtn.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true, 1, 1)); chooseBtn.setText("Choose..."); // $NLX-ManifestEditorPage.Choose-1$ chooseBtn.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { if (BluemixUtil.isServerConfigured()) { boolean success = false; try { // Retrieve the Services List from the Cloud Space ProgressMonitorDialog dialog = new ProgressMonitorDialog(getShell()); dialog.run(true, true, new GetBluemixServices()); success = true; } catch (InvocationTargetException e) { MessageDialog.openError(getShell(), "Error retrieving services", BluemixUtil.getErrorText(e)); // $NLX-ManifestEditorPage.ErrorRetrievingServices-1$ } catch (InterruptedException e) { // Ignore } if (success) { // Open the Services Dialog if (_cloudServices.size() == 0) { MessageDialog.openInformation(getShell(), BluemixUtil.productizeString("%BM_PRODUCT% Services"), "There are no defined services in this Cloud Space"); // $NLX-ManifestEditorPage.IBMBluemixServices-1$ $NLX-ManifestEditorPage.TherearenodefinedServicesinthisCl-2$ } else { ManifestServicesDialog dialog = new ManifestServicesDialog(getShell(), _cloudServices, _serviceList); if(dialog.open() == Dialog.OK) { updateServices(); _serviceTableEditor.refresh(); } } } } } }); section.setClient(container); } @Override public void refreshUI() { refreshTables(); refreshRouteControlState(); } // Refresh the Edit Tables from the bean private void refreshTables() { if (_mpe.getBean().isManifestValid()) { // Services List<String> beanList = _mpe.getBean().getManifestProperties().getServices(); _serviceList.clear(); if (beanList != null) { for (String entry : beanList) { _serviceList.add(new TableEntry(entry)); } } _serviceTableEditor.refresh(); // Hosts beanList = _mpe.getBean().getManifestProperties().getHosts(); _hostList.clear(); if (beanList != null) { for (String entry : beanList) { _hostList.add(new TableEntry(entry)); } } _hostTableEditor.refresh(); // Domains beanList = _mpe.getBean().getManifestProperties().getDomains(); _domainList.clear(); if (beanList != null) { for (String entry : beanList) { _domainList.add(new TableEntry(entry)); } } _domainTableEditor.refresh(); } } // Update the Bean from the Services Table and update the src editor public void updateServices() { if (_serviceList.size() > 0) { List<String> beanList = _mpe.getBean().getManifestProperties().getServices(); if (beanList == null) { beanList = new ArrayList<String>(); _mpe.getBean().getManifestProperties().setServices(beanList); } beanList.clear(); for (EditTableItem service:_serviceList) { // Make sure they're unique if (!beanList.contains(service.getColumn(0))) { beanList.add(service.getColumn(0)); } } } else { _mpe.getBean().getManifestProperties().setServices(null); } _mpe.writeContentsFromBean(); } // Update the Bean from the Hosts Table and update the src editor public void updateHosts() { if (_hostList.size() > 0) { List<String> beanList = _mpe.getBean().getManifestProperties().getHosts(); if (beanList == null) { beanList = new ArrayList<String>(); _mpe.getBean().getManifestProperties().setHosts(beanList); } beanList.clear(); for (EditTableItem host:_hostList) { // Make sure they're unique if (!beanList.contains(host.getColumn(0))) { beanList.add(host.getColumn(0)); } } } else { _mpe.getBean().getManifestProperties().setHosts(null); } _mpe.writeContentsFromBean(); } // Update the Bean from the Domains Table and update the src editor public void updateDomains() { if (_domainList.size() > 0) { List<String> beanList = _mpe.getBean().getManifestProperties().getDomains(); if (beanList == null) { beanList = new ArrayList<String>(); _mpe.getBean().getManifestProperties().setDomains(beanList); } beanList.clear(); for (EditTableItem domain:_domainList) { // Make sure they're unique if (!beanList.contains(domain.getColumn(0))) { beanList.add(domain.getColumn(0)); } } } else { _mpe.getBean().getManifestProperties().setDomains(null); } _mpe.writeContentsFromBean(); } @Override public void contentsChanged(String controlId) { // Callback from ManifestTableEditor that something has changed if (StringUtil.equalsIgnoreCase(controlId, "bluemix.hosts")) { // $NON-NLS-1$ updateHosts(); } else if (StringUtil.equalsIgnoreCase(controlId, "bluemix.domains")) { // $NON-NLS-1$ updateDomains(); } else if (StringUtil.equalsIgnoreCase(controlId, "bluemix.services")) { // $NON-NLS-1$ updateServices(); } } public void refreshRouteControlState() { boolean enable = !_noRouteCheckbox.getSelection(); for (Control control: _routeControls) { control.setEnabled(enable); } } // Utility class used in Table editing public static class TableEntry extends EditTableItem { private String _value; public TableEntry(String value) { _value = value; } @Override public String getColumn(int col) { return _value; } @Override public String getValue(String item) { return _value; } @Override public void setValue(String item, String value) { _value = value; } } // Utility class for retrieving the Services from Bluemix private class GetBluemixServices implements IRunnableWithProgress { public GetBluemixServices() { } @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { monitor.beginTask("Retrieving services...", IProgressMonitor.UNKNOWN); // $NLX-ManifestEditorPage.RetrievingServices-1$ try { _cloudServices.clear(); monitor.subTask("Connecting to Cloud Space"); // $NLX-ManifestEditorPage.ConnectingtoCloudSpace-1$ if (monitor.isCanceled()) { throw new InterruptedException(); } // Get the credentials BluemixConfig config = ConfigManager.getInstance().getConfig(_mpe.getDesignerProject()); String server = PreferencePage.getSecurePreference(KEY_BLUEMIX_SERVER_URL, ""); String user = PreferencePage.getSecurePreference(KEY_BLUEMIX_SERVER_USERNAME, ""); String password = PreferencePage.getSecurePreference(KEY_BLUEMIX_SERVER_PASSWORD, ""); CloudCredentials credentials = new CloudCredentials(user, password); // Login CloudFoundryClient client = new CloudFoundryClient(credentials, URI.create(server).toURL(), config.org, config.space); client.login(); if (monitor.isCanceled()) { throw new InterruptedException(); } // Get the Services monitor.subTask("Reading services"); // $NLX-ManifestEditorPage.ReadingServices-1$ List<CloudService> services = client.getServices(); if (services != null) { for (CloudService service : services) { _cloudServices.add(service); } } } catch (InterruptedException e) { throw(e); } catch (Throwable e) { throw new InvocationTargetException(e); } } } }