/**
* Copyright (c) 2011, 2013 Gunnar Wagenknecht 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:
* Gunnar Wagenknecht - initial API and implementation
* Andreas Mihm - rework new admin ui
*/
package org.eclipse.gyrex.admin.ui.http.internal;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.TreeSet;
import org.eclipse.gyrex.admin.ui.internal.widgets.NonBlockingStatusDialog;
import org.eclipse.gyrex.admin.ui.internal.wizards.dialogfields.ComboDialogField;
import org.eclipse.gyrex.admin.ui.internal.wizards.dialogfields.DialogField;
import org.eclipse.gyrex.admin.ui.internal.wizards.dialogfields.IDialogFieldListener;
import org.eclipse.gyrex.admin.ui.internal.wizards.dialogfields.IListAdapter;
import org.eclipse.gyrex.admin.ui.internal.wizards.dialogfields.LayoutUtil;
import org.eclipse.gyrex.admin.ui.internal.wizards.dialogfields.ListDialogField;
import org.eclipse.gyrex.admin.ui.internal.wizards.dialogfields.ListDialogField.ColumnsDescription;
import org.eclipse.gyrex.admin.ui.internal.wizards.dialogfields.Separator;
import org.eclipse.gyrex.admin.ui.internal.wizards.dialogfields.StringDialogField;
import org.eclipse.gyrex.common.identifiers.IdHelper;
import org.eclipse.gyrex.context.IRuntimeContext;
import org.eclipse.gyrex.context.definitions.ContextDefinition;
import org.eclipse.gyrex.context.internal.ContextActivator;
import org.eclipse.gyrex.context.registry.IRuntimeContextRegistry;
import org.eclipse.gyrex.http.internal.HttpActivator;
import org.eclipse.gyrex.http.internal.application.manager.ApplicationManager;
import org.eclipse.gyrex.http.internal.application.manager.ApplicationProviderRegistration;
import org.eclipse.gyrex.http.internal.application.manager.ApplicationRegistration;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.fieldassist.ContentProposal;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.window.Window;
import org.eclipse.rap.rwt.widgets.DialogCallback;
import org.eclipse.swt.SWT;
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.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.apache.commons.lang.StringUtils;
@SuppressWarnings("restriction")
public class EditApplicationDialog extends NonBlockingStatusDialog {
private static final class PropertiesFieldLabelProvider extends LabelProvider implements ITableLabelProvider {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
@Override
public Image getColumnImage(final Object element, final int columnIndex) {
// no image
return null;
}
@Override
public String getColumnText(final Object element, final int columnIndex) {
if (element instanceof String[])
return ((String[]) element)[columnIndex];
return getText(element);
}
}
/** serialVersionUID */
private static final long serialVersionUID = 1L;
private final StringDialogField idField = new StringDialogField();
private final ComboDialogField providerField = new ComboDialogField(SWT.DROP_DOWN | SWT.READ_ONLY);
private final Map<String, String> providerItemToIdMap = new HashMap<String, String>();
private final StringDialogField contextPathField = new StringDialogField();
private final ListDialogField propertiesField;
{
propertiesField = new ListDialogField(new IListAdapter() {
@Override
public void customButtonPressed(final ListDialogField field, final int index) {
switch (index) {
case 0:
addNewProperty();
break;
case 1:
editSelectedProperty();
break;
}
}
@Override
public void doubleClicked(final ListDialogField field) {
editSelectedProperty();
}
@Override
public void selectionChanged(final ListDialogField field) {
// nothing to do
}
}, new String[] { "Add...", "Edit...", "Remove" }, new PropertiesFieldLabelProvider()) {
@Override
protected int getListStyle() {
return SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION;
}
};
propertiesField.setRemoveButtonIndex(2);
propertiesField.setTableColumns(new ColumnsDescription(new String[] { "Key", "Value" }, true));
}
private final ListDialogField mountsField;
{
mountsField = new ListDialogField(new IListAdapter() {
@Override
public void customButtonPressed(final ListDialogField field, final int index) {
switch (index) {
case 0:
addNewMount();
break;
}
}
@Override
public void doubleClicked(final ListDialogField field) {
editSelectedProperty();
}
@Override
public void selectionChanged(final ListDialogField field) {
// nothing to do
}
}, new String[] { "Add...", "Remove" }, new LabelProvider());
mountsField.setRemoveButtonIndex(1);
mountsField.setViewerComparator(new ViewerComparator(Collator.getInstance(Locale.US)));
}
private final ApplicationManager applicationManager;
private final SortedMap<String, String> applicationProperties = new TreeMap<String, String>();
private final ApplicationRegistration applicationRegistration;
/**
* Creates a new instance.
*
* @param parent
*/
public EditApplicationDialog(final Shell parent, final ApplicationManager applicationManager, final ApplicationRegistration applicationRegistration) {
super(parent);
this.applicationManager = applicationManager;
this.applicationRegistration = applicationRegistration;
setTitle(null == applicationRegistration ? "New Application" : "Edit Application");
setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL);
}
void addNewMount() {
final MountApplicationDialog dialog = new MountApplicationDialog(getParentShell());
dialog.openNonBlocking(new DialogCallback() {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
@Override
public void dialogClosed(final int returnCode) {
if (returnCode == Window.OK) {
mountsField.addElement(dialog.getUrl().toExternalForm());
}
}
});
}
void addNewProperty() {
final EditPropertyDialog dialog = new EditPropertyDialog(getParentShell(), null, null);
dialog.openNonBlocking(new DialogCallback() {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
@Override
public void dialogClosed(final int returnCode) {
if (returnCode == Window.OK) {
applicationProperties.put(dialog.getKey(), dialog.getValue());
refreshProperties();
}
}
});
}
@Override
protected Control createDialogArea(final Composite parent) {
final Composite composite = (Composite) super.createDialogArea(parent);
final GridData gd = (GridData) composite.getLayoutData();
gd.minimumHeight = convertVerticalDLUsToPixels(200);
gd.minimumWidth = convertHorizontalDLUsToPixels(400);
idField.setLabelText("Id");
contextPathField.setLabelText("Context");
providerField.setLabelText("Provider");
final IDialogFieldListener validateListener = new IDialogFieldListener() {
@Override
public void dialogFieldChanged(final DialogField field) {
validate();
}
};
idField.setDialogFieldListener(validateListener);
contextPathField.setDialogFieldListener(validateListener);
providerField.setDialogFieldListener(validateListener);
providerItemToIdMap.clear();
final TreeSet<String> providerItems = new TreeSet<String>();
final Collection<ApplicationProviderRegistration> providers = HttpActivator.getInstance().getProviderRegistry().getRegisteredProviders().values();
for (final ApplicationProviderRegistration registration : providers) {
final String label = HttpUiAdapter.getLabel(registration);
providerItemToIdMap.put(label, registration.getProviderId());
providerItems.add(label);
}
providerField.setItems(providerItems.toArray(new String[providerItems.size()]));
contextPathField.setContentProposalProcessor(new IContentProposalProvider() {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
@Override
public IContentProposal[] getProposals(final String contents, final int position) {
final List<IContentProposal> resultList = new ArrayList<IContentProposal>();
final String patternString = StringUtils.trimToNull(StringUtils.substring(contents, 0, position));
final Collection<ContextDefinition> contexts = ContextActivator.getInstance().getContextRegistryImpl().getDefinedContexts();
for (final ContextDefinition contextDefinition : contexts) {
if ((null == patternString) || StringUtils.contains(contextDefinition.getPath().toString(), patternString)) {
resultList.add(new ContentProposal(contextDefinition.getPath().toString(), contextDefinition.toString()));
}
}
return resultList.toArray(new IContentProposal[resultList.size()]);
}
});
propertiesField.setLabelText("Properties");
mountsField.setLabelText("Mounts");
final Text warning = new Text(composite, SWT.WRAP | SWT.READ_ONLY);
warning.setText("Warning: this dialog is ugly. Please help us improve the UI. Any mockups and/or patches are very much appreciated!");
warning.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
LayoutUtil.doDefaultLayout(composite, new DialogField[] { new Separator(), idField, providerField, contextPathField, new Separator(), propertiesField, mountsField }, false);
LayoutUtil.setHorizontalGrabbing(idField.getTextControl(null));
LayoutUtil.setHorizontalGrabbing(providerField.getComboControl(null));
LayoutUtil.setHorizontalGrabbing(contextPathField.getTextControl(null));
LayoutUtil.setHorizontalGrabbing(propertiesField.getListControl(null));
LayoutUtil.setHorizontalGrabbing(mountsField.getListControl(null));
if (null != applicationRegistration) {
idField.setText(applicationRegistration.getApplicationId());
idField.setEnabled(false);
contextPathField.setText(applicationRegistration.getContext().getContextPath().toString());
contextPathField.setEnabled(false);
for (final Entry<String, String> e : providerItemToIdMap.entrySet()) {
if (e.getValue().equals(applicationRegistration.getProviderId())) {
providerField.selectItem(e.getKey());
}
}
providerField.setEnabled(false);
applicationProperties.putAll(applicationRegistration.getInitProperties());
mountsField.setElements(applicationManager.getMounts(applicationRegistration.getApplicationId()));
}
refreshProperties();
final GridLayout masterLayout = (GridLayout) composite.getLayout();
masterLayout.marginWidth = 5;
masterLayout.marginHeight = 5;
LayoutUtil.setHorizontalSpan(warning, masterLayout.numColumns);
return composite;
}
void editSelectedProperty() {
final List selectedElements = propertiesField.getSelectedElements();
if (selectedElements.isEmpty())
return;
final String[] elem = (String[]) selectedElements.get(0);
final EditPropertyDialog dialog = new EditPropertyDialog(getParentShell(), elem[0], elem[1]);
dialog.openNonBlocking(new DialogCallback() {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
@Override
public void dialogClosed(final int returnCode) {
if (returnCode == Window.OK) {
applicationProperties.put(dialog.getKey(), dialog.getValue());
refreshProperties();
}
}
});
}
@Override
protected void okPressed() {
validate();
if (!getStatus().isOK())
return;
try {
// refresh properties
applicationProperties.clear();
for (final Object property : propertiesField.getElements()) {
applicationProperties.put(((String[]) property)[0], ((String[]) property)[1]);
}
// create/update application
if (null == applicationRegistration) {
final String id = idField.getText();
final String providerId = providerItemToIdMap.get(providerField.getText());
final String contextPath = contextPathField.getText();
final IRuntimeContext context = HttpUiActivator.getInstance().getService(IRuntimeContextRegistry.class).get(new Path(contextPath).makeAbsolute().addTrailingSeparator());
applicationManager.register(id, providerId, context, applicationProperties);
} else {
applicationManager.setProperties(applicationRegistration.getApplicationId(), applicationProperties);
}
// update mounts
final List applicationMounts = mountsField.getElements();
final Collection<String> existingMounts = null != applicationRegistration ? applicationManager.getMounts(applicationRegistration.getApplicationId()) : new ArrayList<String>(1);
for (final String url : existingMounts) {
if (!applicationMounts.contains(url)) {
applicationManager.unmount(url);
}
}
for (final Object url : applicationMounts) {
if (!existingMounts.contains(url)) {
applicationManager.mount((String) url, null != applicationRegistration ? applicationRegistration.getApplicationId() : idField.getText());
}
}
} catch (final Exception e) {
ErrorDialog.openError(getParentShell(), "Error", "An error occured saving the application.", getStatus());
// don't abort, i.e. close window
}
super.okPressed();
}
private void refreshProperties() {
final List<String[]> elements = new ArrayList<String[]>(applicationProperties.size());
for (final Entry<String, String> entry : applicationProperties.entrySet()) {
elements.add(new String[] { entry.getKey(), entry.getValue() });
}
propertiesField.setElements(elements);
}
void setError(final String message) {
updateStatus(new Status(IStatus.ERROR, HttpUiActivator.SYMBOLIC_NAME, message));
getShell().pack(true);
}
void setInfo(final String message) {
updateStatus(new Status(IStatus.INFO, HttpUiActivator.SYMBOLIC_NAME, message));
}
void setWarning(final String message) {
updateStatus(new Status(IStatus.WARNING, HttpUiActivator.SYMBOLIC_NAME, message));
}
void validate() {
final String id = idField.getText();
if (StringUtils.isBlank(id)) {
setInfo("Please enter an id.");
return;
}
if (!IdHelper.isValidId(id)) {
setError("The entered id is invalid. It may only contain ASCII chars a-z, 0-9, '.', '-' and/or '_'.");
return;
}
final String providerLabel = providerField.getText();
if (StringUtils.isBlank(providerLabel)) {
setInfo("Please select a provider.");
return;
}
final String path = contextPathField.getText();
if (StringUtils.isBlank(path)) {
setInfo("Please enter a context path.");
return;
}
if (!Path.EMPTY.isValidPath(path)) {
setError("The entered context path is invalid. It may only contain ASCII chars a-z, 0-9, '.', '-' and/or '_' and '/' as separator.");
return;
}
final IRuntimeContextRegistry registry = HttpUiActivator.getInstance().getService(IRuntimeContextRegistry.class);
final IRuntimeContext context = registry.get(new Path(path));
if (null == context) {
setError("The context is not defined!");
return;
}
updateStatus(Status.OK_STATUS);
}
}