/******************************************************************************* * Copyright (c) 2010, 2016 Ericsson * * 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: * Patrick Tasse - Initial API and implementation *******************************************************************************/ package org.eclipse.tracecompass.internal.tmf.ui.parsers.wizards; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.text.ParseException; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.viewers.AbstractTreeViewer; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.browser.Browser; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.tracecompass.internal.tmf.ui.Activator; import org.eclipse.tracecompass.internal.tmf.ui.Messages; import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomTraceDefinition; import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomTraceDefinition.Tag; import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlInputAttribute; import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlInputElement; import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlTrace; import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlTraceDefinition; import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType; import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper; import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat; import org.osgi.framework.Bundle; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import com.google.common.base.Joiner; /** * Input wizard page for custom XML trace parsers. * * @author Patrick Tasse */ public class CustomXmlParserInputWizardPage extends WizardPage { private static final String DEFAULT_TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; //$NON-NLS-1$ private static final String TIMESTAMP_FORMAT_BUNDLE = "org.eclipse.tracecompass.doc.user"; //$NON-NLS-1$ private static final String TIMESTAMP_FORMAT_PATH = "reference/api/org/eclipse/tracecompass/tmf/core/timestamp/TmfTimestampFormat.html"; //$NON-NLS-1$ private static final Image ELEMENT_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/element_icon.gif"); //$NON-NLS-1$ private static final Image ADD_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/add_button.gif"); //$NON-NLS-1$ private static final Image ADD_NEXT_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/addnext_button.gif"); //$NON-NLS-1$ private static final Image ADD_CHILD_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/addchild_button.gif"); //$NON-NLS-1$ private static final Image ADD_MANY_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/addmany_button.gif"); //$NON-NLS-1$ private static final Image DELETE_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/delete_button.gif"); //$NON-NLS-1$ private static final Image MOVE_UP_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/moveup_button.gif"); //$NON-NLS-1$ private static final Image MOVE_DOWN_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/movedown_button.gif"); //$NON-NLS-1$ private static final Image HELP_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/help_button.gif"); //$NON-NLS-1$ private static final Color COLOR_LIGHT_RED = new Color(Display.getDefault(), 255, 192, 192); private static final Color COLOR_TEXT_BACKGROUND = Display.getDefault().getSystemColor(SWT.COLOR_WHITE); private static final Color COLOR_WIDGET_BACKGROUND = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); private static final Color COLOR_GRAY = Display.getDefault().getSystemColor(SWT.COLOR_GRAY); private final ISelection selection; private CustomXmlTraceDefinition definition; private String editCategoryName; private String editDefinitionName; private String defaultDescription; private ElementNode selectedElement; private Composite container; private Text categoryText; private Text logtypeText; private Text timeStampOutputFormatText; private Text timeStampPreviewText; private Button removeButton; private Button addChildButton; private Button addNextButton; private Button moveUpButton; private Button moveDownButton; private ScrolledComposite elementScrolledComposite; private TreeViewer treeViewer; private Composite elementContainer; private Text errorText; private StyledText inputText; private Font fixedFont; private UpdateListener updateListener; private Browser helpBrowser; private Element documentElement; // variables used recursively through element traversal private String timeStampValue; private String timeStampFormat; private boolean timeStampFound; private int logEntriesCount; private boolean logEntryFound; /** * Constructor * * @param selection * Selection object * @param definition * Trace definition */ protected CustomXmlParserInputWizardPage(ISelection selection, CustomXmlTraceDefinition definition) { super("CustomXmlParserWizardPage"); //$NON-NLS-1$ if (definition == null) { setTitle(Messages.CustomXmlParserInputWizardPage_titleNew); defaultDescription = Messages.CustomXmlParserInputWizardPage_descriptionNew; } else { setTitle(Messages.CustomXmlParserInputWizardPage_titleEdit); defaultDescription = Messages.CustomXmlParserInputWizardPage_descriptionEdit; } setDescription(defaultDescription); this.selection = selection; this.definition = definition; if (definition != null) { this.editCategoryName = definition.categoryName; this.editDefinitionName = definition.definitionName; } } @Override public void createControl(Composite parent) { container = new Composite(parent, SWT.NULL); container.setLayout(new GridLayout()); updateListener = new UpdateListener(); Composite headerComposite = new Composite(container, SWT.FILL); GridLayout headerLayout = new GridLayout(5, false); headerLayout.marginHeight = 0; headerLayout.marginWidth = 0; headerComposite.setLayout(headerLayout); headerComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); Label categoryLabel = new Label(headerComposite, SWT.NULL); categoryLabel.setText(Messages.CustomXmlParserInputWizardPage_category); categoryText = new Text(headerComposite, SWT.BORDER | SWT.SINGLE); categoryText.setLayoutData(new GridData(120, SWT.DEFAULT)); Label timeStampFormatLabel = new Label(headerComposite, SWT.NULL); timeStampFormatLabel.setText(Messages.CustomXmlParserInputWizardPage_timestampFormat); timeStampOutputFormatText = new Text(headerComposite, SWT.BORDER | SWT.SINGLE); timeStampOutputFormatText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); timeStampOutputFormatText.setText(DEFAULT_TIMESTAMP_FORMAT); timeStampOutputFormatText.addPaintListener(e -> { if (!timeStampOutputFormatText.isFocusControl() && timeStampOutputFormatText.getText().trim().isEmpty()) { e.gc.setForeground(COLOR_GRAY); int borderWidth = timeStampOutputFormatText.getBorderWidth(); e.gc.drawText(Messages.CustomXmlParserInputWizardPage_default, borderWidth, borderWidth); } }); Button timeStampFormatHelpButton = new Button(headerComposite, SWT.PUSH); timeStampFormatHelpButton.setImage(HELP_IMAGE); timeStampFormatHelpButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_timestampFormatHelp); timeStampFormatHelpButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { Bundle plugin = Platform.getBundle(TIMESTAMP_FORMAT_BUNDLE); IPath path = new Path(TIMESTAMP_FORMAT_PATH); URL fileURL = FileLocator.find(plugin, path, null); try { URL pageURL = FileLocator.toFileURL(fileURL); openHelpShell(pageURL.toString()); } catch (IOException e1) { } } }); Label logtypeLabel = new Label(headerComposite, SWT.NULL); logtypeLabel.setText(Messages.CustomXmlParserInputWizardPage_logType); logtypeText = new Text(headerComposite, SWT.BORDER | SWT.SINGLE); logtypeText.setLayoutData(new GridData(120, SWT.DEFAULT)); logtypeText.setFocus(); Label timeStampPreviewLabel = new Label(headerComposite, SWT.NULL); timeStampPreviewLabel.setText(Messages.CustomXmlParserInputWizardPage_preview); timeStampPreviewText = new Text(headerComposite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY); timeStampPreviewText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); timeStampPreviewText.setText("*no time stamp element or attribute*"); //$NON-NLS-1$ createButtonBar(); SashForm vSash = new SashForm(container, SWT.VERTICAL); vSash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); vSash.setBackground(COLOR_GRAY); SashForm hSash = new SashForm(vSash, SWT.HORIZONTAL); hSash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); ScrolledComposite treeScrolledComposite = new ScrolledComposite(hSash, SWT.V_SCROLL | SWT.H_SCROLL); treeScrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); Composite treeContainer = new Composite(treeScrolledComposite, SWT.NONE); treeContainer.setLayout(new FillLayout()); treeScrolledComposite.setContent(treeContainer); treeScrolledComposite.setExpandHorizontal(true); treeScrolledComposite.setExpandVertical(true); treeViewer = new TreeViewer(treeContainer, SWT.SINGLE | SWT.BORDER); treeViewer.setContentProvider(new InputElementTreeNodeContentProvider()); treeViewer.setLabelProvider(new InputElementTreeLabelProvider()); treeViewer.addSelectionChangedListener(new InputElementTreeSelectionChangedListener()); treeContainer.layout(); treeScrolledComposite .setMinSize(treeContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).x, treeContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).y); elementScrolledComposite = new ScrolledComposite(hSash, SWT.V_SCROLL); elementScrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); elementContainer = new Composite(elementScrolledComposite, SWT.NONE); GridLayout gl = new GridLayout(); gl.marginHeight = 1; gl.marginWidth = 0; elementContainer.setLayout(gl); elementScrolledComposite.setContent(elementContainer); elementScrolledComposite.setExpandHorizontal(true); elementScrolledComposite.setExpandVertical(true); if (definition == null) { definition = new CustomXmlTraceDefinition(); } loadDefinition(definition); treeViewer.expandAll(); elementContainer.layout(); categoryText.addModifyListener(updateListener); logtypeText.addModifyListener(updateListener); timeStampOutputFormatText.addModifyListener(updateListener); elementScrolledComposite.setMinSize(elementContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).x, elementContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).y - 1); hSash.setWeights(new int[] { 1, 2 }); if (definition.rootInputElement == null) { removeButton.setEnabled(false); addChildButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_addDocumentElement); addNextButton.setEnabled(false); moveUpButton.setEnabled(false); moveDownButton.setEnabled(false); } else { // root is selected addNextButton.setEnabled(false); } Composite sashBottom = new Composite(vSash, SWT.NONE); GridLayout sashBottomLayout = new GridLayout(2, false); sashBottomLayout.marginHeight = 0; sashBottomLayout.marginWidth = 0; sashBottom.setLayout(sashBottomLayout); Label previewLabel = new Label(sashBottom, SWT.NULL); previewLabel.setText(Messages.CustomXmlParserInputWizardPage_previewInput); errorText = new Text(sashBottom, SWT.SINGLE | SWT.READ_ONLY); errorText.setBackground(COLOR_WIDGET_BACKGROUND); errorText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); errorText.setVisible(false); inputText = new StyledText(sashBottom, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL); if (fixedFont == null) { if (System.getProperty("os.name").contains("Windows")) { //$NON-NLS-1$ //$NON-NLS-2$ fixedFont = new Font(Display.getCurrent(), new FontData("Courier New", 10, SWT.NORMAL)); //$NON-NLS-1$ } else { fixedFont = new Font(Display.getCurrent(), new FontData("Monospace", 10, SWT.NORMAL)); //$NON-NLS-1$ } } inputText.setFont(fixedFont); GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1); gd.heightHint = inputText.computeSize(SWT.DEFAULT, inputText.getLineHeight() * 4).y; gd.widthHint = 800; inputText.setLayoutData(gd); inputText.setText(getSelectionText()); inputText.addModifyListener(e -> parseXmlInput(inputText.getText())); inputText.addModifyListener(updateListener); vSash.setWeights(new int[] { hSash.computeSize(SWT.DEFAULT, SWT.DEFAULT).y, sashBottom.computeSize(SWT.DEFAULT, SWT.DEFAULT).y }); setControl(container); } private void createButtonBar() { Composite buttonBar = new Composite(container, SWT.NONE); GridLayout buttonBarLayout = new GridLayout(6, false); buttonBarLayout.marginHeight = 0; buttonBarLayout.marginWidth = 0; buttonBar.setLayout(buttonBarLayout); removeButton = new Button(buttonBar, SWT.PUSH); removeButton.setImage(DELETE_IMAGE); removeButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_removeElement); removeButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (treeViewer.getSelection().isEmpty() || selectedElement == null) { return; } removeElement(); CustomXmlInputElement inputElement = (CustomXmlInputElement) ((IStructuredSelection) treeViewer.getSelection()).getFirstElement(); if (inputElement == definition.rootInputElement) { definition.rootInputElement = null; } else { inputElement.getParentElement().getChildElements().remove(inputElement); } treeViewer.refresh(); validate(); updatePreviews(); removeButton.setEnabled(false); if (definition.rootInputElement == null) { addChildButton.setEnabled(true); addChildButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_addDocumentEleemnt); } else { addChildButton.setEnabled(false); } addNextButton.setEnabled(false); moveUpButton.setEnabled(false); moveDownButton.setEnabled(false); } }); addChildButton = new Button(buttonBar, SWT.PUSH); addChildButton.setImage(ADD_CHILD_IMAGE); addChildButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_addChildElement); addChildButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { CustomXmlInputElement inputElement = new CustomXmlInputElement("", false, Tag.IGNORE, Tag.IGNORE.toString(), 0, "", null); //$NON-NLS-1$ //$NON-NLS-2$ if (definition.rootInputElement == null) { definition.rootInputElement = inputElement; inputElement.setElementName(getChildNameSuggestion(null)); } else if (treeViewer.getSelection().isEmpty()) { return; } else { CustomXmlInputElement parentInputElement = (CustomXmlInputElement) ((IStructuredSelection) treeViewer.getSelection()).getFirstElement(); parentInputElement.addChild(inputElement); inputElement.setElementName(getChildNameSuggestion(parentInputElement)); } treeViewer.refresh(); treeViewer.setSelection(new StructuredSelection(inputElement), true); } }); addNextButton = new Button(buttonBar, SWT.PUSH); addNextButton.setImage(ADD_NEXT_IMAGE); addNextButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_addNextElement); addNextButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { CustomXmlInputElement inputElement = new CustomXmlInputElement("", false, Tag.IGNORE, Tag.IGNORE.toString(), 0, "", null); //$NON-NLS-1$ //$NON-NLS-2$ if (definition.rootInputElement == null) { definition.rootInputElement = inputElement; inputElement.setElementName(getChildNameSuggestion(null)); } else if (treeViewer.getSelection().isEmpty()) { return; } else { CustomXmlInputElement previousInputElement = (CustomXmlInputElement) ((IStructuredSelection) treeViewer.getSelection()).getFirstElement(); if (previousInputElement == definition.rootInputElement) { return; } previousInputElement.addNext(inputElement); inputElement.setElementName(getChildNameSuggestion(inputElement.getParentElement())); } treeViewer.refresh(); treeViewer.setSelection(new StructuredSelection(inputElement), true); } }); Button feelingLuckyButton = new Button(buttonBar, SWT.PUSH); feelingLuckyButton.setImage(ADD_MANY_IMAGE); feelingLuckyButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_feelingLucky); feelingLuckyButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { CustomXmlInputElement inputElement = null; if (definition.rootInputElement == null) { if (getChildNameSuggestion(null).length() != 0) { inputElement = new CustomXmlInputElement(getChildNameSuggestion(null), false, Tag.IGNORE, Tag.IGNORE.toString(), 0, "", null); //$NON-NLS-1$ definition.rootInputElement = inputElement; feelingLucky(inputElement); } else { return; } } else if (treeViewer.getSelection().isEmpty()) { return; } else { inputElement = (CustomXmlInputElement) ((IStructuredSelection) treeViewer.getSelection()).getFirstElement(); feelingLucky(inputElement); } treeViewer.refresh(); treeViewer.setSelection(new StructuredSelection(inputElement), true); treeViewer.expandToLevel(inputElement, AbstractTreeViewer.ALL_LEVELS); } }); moveUpButton = new Button(buttonBar, SWT.PUSH); moveUpButton.setImage(MOVE_UP_IMAGE); moveUpButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_moveUp); moveUpButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (treeViewer.getSelection().isEmpty()) { return; } CustomXmlInputElement inputElement = (CustomXmlInputElement) ((IStructuredSelection) treeViewer.getSelection()).getFirstElement(); if (inputElement == definition.rootInputElement) { return; } inputElement.moveUp(); treeViewer.refresh(); validate(); updatePreviews(); } }); moveDownButton = new Button(buttonBar, SWT.PUSH); moveDownButton.setImage(MOVE_DOWN_IMAGE); moveDownButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_moveDown); moveDownButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (treeViewer.getSelection().isEmpty()) { return; } CustomXmlInputElement inputElement = (CustomXmlInputElement) ((IStructuredSelection) treeViewer.getSelection()).getFirstElement(); if (inputElement == definition.rootInputElement) { return; } inputElement.moveDown(); treeViewer.refresh(); validate(); updatePreviews(); } }); } private void feelingLucky(CustomXmlInputElement inputElement) { while (true) { String attributeName = getAttributeNameSuggestion(inputElement); if (attributeName.length() == 0) { break; } CustomXmlInputAttribute attribute = new CustomXmlInputAttribute(attributeName, Tag.OTHER, attributeName, 0, ""); //$NON-NLS-1$ inputElement.addAttribute(attribute); } while (true) { String childName = getChildNameSuggestion(inputElement); if (childName.length() == 0) { break; } CustomXmlInputElement childElement = new CustomXmlInputElement(childName, false, Tag.IGNORE, Tag.IGNORE.toString(), 0, "", null); //$NON-NLS-1$ inputElement.addChild(childElement); feelingLucky(childElement); } } private static class InputElementTreeNodeContentProvider implements ITreeContentProvider { @Override public Object[] getElements(Object inputElement) { CustomXmlTraceDefinition def = (CustomXmlTraceDefinition) inputElement; if (def.rootInputElement != null) { return new Object[] { def.rootInputElement }; } return new Object[0]; } @Override public Object[] getChildren(Object parentElement) { CustomXmlInputElement inputElement = (CustomXmlInputElement) parentElement; if (inputElement.getChildElements() == null) { return new CustomXmlInputElement[0]; } return inputElement.getChildElements().toArray(); } @Override public boolean hasChildren(Object element) { CustomXmlInputElement inputElement = (CustomXmlInputElement) element; return (inputElement.getChildElements() != null && inputElement.getChildElements().size() > 0); } @Override public void dispose() { } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public Object getParent(Object element) { CustomXmlInputElement inputElement = (CustomXmlInputElement) element; return inputElement.getParentElement(); } } private static class InputElementTreeLabelProvider extends ColumnLabelProvider { @Override public Image getImage(Object element) { return ELEMENT_IMAGE; } @Override public String getText(Object element) { CustomXmlInputElement inputElement = (CustomXmlInputElement) element; return (inputElement.getElementName().trim().length() == 0) ? "?" : inputElement.getElementName(); //$NON-NLS-1$ } } private class InputElementTreeSelectionChangedListener implements ISelectionChangedListener { @Override public void selectionChanged(SelectionChangedEvent event) { if (selectedElement != null) { selectedElement.dispose(); } if (!(event.getSelection().isEmpty()) && event.getSelection() instanceof IStructuredSelection) { IStructuredSelection sel = (IStructuredSelection) event.getSelection(); CustomXmlInputElement inputElement = (CustomXmlInputElement) sel.getFirstElement(); selectedElement = new ElementNode(elementContainer, inputElement); elementContainer.layout(); elementScrolledComposite.setMinSize(elementContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).x, elementContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).y - 1); container.layout(); validate(); updatePreviews(); removeButton.setEnabled(true); addChildButton.setEnabled(true); addChildButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_addChildElement); if (definition.rootInputElement == inputElement) { addNextButton.setEnabled(false); } else { addNextButton.setEnabled(true); } moveUpButton.setEnabled(true); moveDownButton.setEnabled(true); } else { removeButton.setEnabled(false); if (definition.rootInputElement == null) { addChildButton.setEnabled(true); addChildButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_addDocumentElement); } else { addChildButton.setEnabled(false); } addNextButton.setEnabled(false); moveUpButton.setEnabled(false); moveDownButton.setEnabled(false); } } } @Override public void dispose() { if (fixedFont != null) { fixedFont.dispose(); fixedFont = null; } super.dispose(); } private void loadDefinition(CustomXmlTraceDefinition def) { categoryText.setText(def.categoryName); logtypeText.setText(def.definitionName); if (def.timeStampOutputFormat != null) { timeStampOutputFormatText.setText(def.timeStampOutputFormat); } else { timeStampOutputFormatText.setText(""); //$NON-NLS-1$ } treeViewer.setInput(def); if (def.rootInputElement != null) { treeViewer.setSelection(new StructuredSelection(def.rootInputElement)); } } private String getName(CustomXmlInputElement inputElement) { String name = (inputElement.getElementName().trim().length() == 0) ? "?" : inputElement.getElementName().trim(); //$NON-NLS-1$ if (inputElement.getParentElement() == null) { return name; } return getName(inputElement.getParentElement()) + " : " + name; //$NON-NLS-1$ } private String getName(CustomXmlInputAttribute inputAttribute, CustomXmlInputElement inputElement) { String name = (inputAttribute.getAttributeName().trim().length() == 0) ? "?" : inputAttribute.getAttributeName().trim(); //$NON-NLS-1$ return getName(inputElement) + " : " + name; //$NON-NLS-1$ } @Override public void setVisible(boolean visible) { if (visible) { validate(); updatePreviews(); } super.setVisible(visible); } /** * Get the global list of inputs. * * @return The list of inputs */ public List<Entry<Tag, String>> getInputs() { return getInputs(definition.rootInputElement); } /** * Get the list of inputs for a given element, recursively. * * @param inputElement * The element * @return The list of inputs */ public List<Entry<Tag, String>> getInputs(CustomXmlInputElement inputElement) { List<Entry<Tag, String>> inputs = new ArrayList<>(); if (inputElement.getInputTag() != null && !inputElement.getInputTag().equals(Tag.IGNORE)) { Entry<Tag, String> input = new SimpleEntry<>(inputElement.getInputTag(), inputElement.getInputName()); if (!inputs.contains(input)) { inputs.add(input); } } if (inputElement.getAttributes() != null) { for (CustomXmlInputAttribute attribute : inputElement.getAttributes()) { Entry<Tag, String> input = new SimpleEntry<>(attribute.getInputTag(), attribute.getInputName()); if (!inputs.contains(input)) { inputs.add(input); } } } if (inputElement.getChildElements() != null) { for (CustomXmlInputElement childInputElement : inputElement.getChildElements()) { for (Entry<Tag, String> input : getInputs(childInputElement)) { if (!inputs.contains(input)) { inputs.add(input); } } } } return inputs; } private void removeElement() { selectedElement.dispose(); selectedElement = null; elementContainer.layout(); elementScrolledComposite.setMinSize(elementContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).x, elementContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).y - 1); container.layout(); } private String getSelectionText() { InputStream inputStream = null; if (this.selection instanceof IStructuredSelection) { Object sel = ((IStructuredSelection) this.selection).getFirstElement(); if (sel instanceof IFile) { IFile file = (IFile) sel; try { inputStream = file.getContents(); } catch (CoreException e) { return ""; //$NON-NLS-1$ } } } if (inputStream != null) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));) { StringBuilder sb = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) { sb.append(line); sb.append('\n'); } parseXmlInput(sb.toString()); return sb.toString(); } catch (IOException e) { return ""; //$NON-NLS-1$ } } return ""; //$NON-NLS-1$ } private void parseXmlInput(final String string) { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); // The following allows xml parsing without access to the dtd EntityResolver resolver = (publicId, systemId) -> { String empty = ""; //$NON-NLS-1$ ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes()); return new InputSource(bais); }; db.setEntityResolver(resolver); // The following catches xml parsing exceptions db.setErrorHandler(new ErrorHandler() { @Override public void error(SAXParseException saxparseexception) throws SAXException { } @Override public void warning(SAXParseException saxparseexception) throws SAXException { } @Override public void fatalError(SAXParseException saxparseexception) throws SAXException { if (string.trim().length() != 0) { errorText.setText(saxparseexception.getMessage()); errorText.setBackground(COLOR_LIGHT_RED); errorText.setVisible(true); } throw saxparseexception; } }); errorText.setVisible(false); Document doc = null; doc = db.parse(new ByteArrayInputStream(string.getBytes())); documentElement = doc.getDocumentElement(); } catch (ParserConfigurationException e) { Activator.getDefault().logError("Error pasing XML input string: " + string, e); //$NON-NLS-1$ documentElement = null; } catch (SAXException e) { documentElement = null; } catch (IOException e) { Activator.getDefault().logError("Error pasing XML input string: " + string, e); //$NON-NLS-1$ documentElement = null; } } private void initValues() { timeStampValue = null; timeStampFormat = null; logEntriesCount = 0; logEntryFound = false; } private void updatePreviews() { if (inputText == null) { // early update during construction return; } inputText.setStyleRanges(new StyleRange[] {}); if (selectedElement == null) { return; } initValues(); selectedElement.updatePreview(); if (timeStampValue != null && timeStampFormat != null) { try { TmfTimestampFormat timestampFormat = new TmfTimestampFormat(timeStampFormat); long timestamp = timestampFormat.parseValue(timeStampValue); if (timeStampOutputFormatText.getText().trim().isEmpty()) { timestampFormat = new TmfTimestampFormat(); } else { timestampFormat = new TmfTimestampFormat(timeStampOutputFormatText.getText().trim()); } timeStampPreviewText.setText(timestampFormat.format(timestamp)); } catch (ParseException e) { timeStampPreviewText.setText("*parse exception* [" + timeStampValue + "] <> [" + timeStampFormat + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } catch (IllegalArgumentException e) { timeStampPreviewText.setText("*parse exception* [Illegal Argument]"); //$NON-NLS-1$ } } else { timeStampPreviewText.setText("*no matching time stamp*"); //$NON-NLS-1$ } } private void openHelpShell(String url) { if (helpBrowser != null && !helpBrowser.isDisposed()) { helpBrowser.getShell().setActive(); if (!helpBrowser.getUrl().equals(url)) { helpBrowser.setUrl(url); } return; } final Shell helpShell = new Shell(getShell(), SWT.SHELL_TRIM); helpShell.setLayout(new FillLayout()); helpBrowser = new Browser(helpShell, SWT.NONE); helpBrowser.addTitleListener(event -> helpShell.setText(event.title)); Rectangle r = container.getBounds(); Point p = container.toDisplay(r.x, r.y); Rectangle trim = helpShell.computeTrim(p.x + (r.width - 750) / 2, p.y + (r.height - 400) / 2, 750, 400); helpShell.setBounds(trim); helpShell.open(); helpBrowser.setUrl(url); } private class UpdateListener implements ModifyListener, SelectionListener { @Override public void modifyText(ModifyEvent e) { validate(); updatePreviews(); } @Override public void widgetDefaultSelected(SelectionEvent e) { validate(); updatePreviews(); } @Override public void widgetSelected(SelectionEvent e) { validate(); updatePreviews(); } } private class ElementNode { private final CustomXmlInputElement inputElement; private final Group group; private List<Attribute> attributes = new ArrayList<>(); private List<ElementNode> childElements = new ArrayList<>(); private Text elementNameText; private Composite tagComposite; private Combo tagCombo; private Label tagLabel; private Text tagText; private Combo actionCombo; private Label previewLabel; private Text previewText; private Button logEntryButton; private Button eventTypeButton; private Text eventTypeText; private Label fillerLabel; private Composite addAttributeComposite; private Button addAttributeButton; private Label addAttributeLabel; public ElementNode(Composite parent, CustomXmlInputElement inputElement) { this.inputElement = inputElement; group = new Group(parent, SWT.NONE); GridLayout gl = new GridLayout(2, false); gl.marginHeight = 0; group.setLayout(gl); group.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); group.setText(getName(inputElement)); Label label = new Label(group, SWT.NULL); label.setText(Messages.CustomXmlParserInputWizardPage_elementName); label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); elementNameText = new Text(group, SWT.BORDER | SWT.SINGLE); GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false); gd.widthHint = 0; elementNameText.setLayoutData(gd); elementNameText.addModifyListener(e -> { ElementNode.this.inputElement.setElementName(elementNameText.getText().trim()); group.setText(getName(ElementNode.this.inputElement)); }); elementNameText.setText(inputElement.getElementName()); elementNameText.addModifyListener(updateListener); if (inputElement.getParentElement() != null) { previewLabel = new Label(group, SWT.NULL); previewLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); previewLabel.setText(Messages.CustomXmlParserInputWizardPage_preview); previewText = new Text(group, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY); gd = new GridData(SWT.FILL, SWT.CENTER, true, false); gd.widthHint = 0; previewText.setLayoutData(gd); previewText.setText(Messages.CustomXmlParserInputWizardPage_noMatchingElement); previewText.setBackground(COLOR_WIDGET_BACKGROUND); logEntryButton = new Button(group, SWT.CHECK); logEntryButton.setText(Messages.CustomXmlParserInputWizardPage_logEntry); logEntryButton.setSelection(inputElement.isLogEntry()); logEntryButton.addSelectionListener(new SelectionListener() { @Override public void widgetDefaultSelected(SelectionEvent e) { } @Override public void widgetSelected(SelectionEvent e) { CustomXmlInputElement parentElem = ElementNode.this.inputElement.getParentElement(); while (parentElem != null) { parentElem.setLogEntry(false); parentElem = parentElem.getParentElement(); } } }); logEntryButton.addSelectionListener(updateListener); tagComposite = new Composite(group, SWT.FILL); GridLayout tagLayout = new GridLayout(4, false); tagLayout.marginWidth = 0; tagLayout.marginHeight = 0; tagComposite.setLayout(tagLayout); tagComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); tagCombo = new Combo(tagComposite, SWT.DROP_DOWN | SWT.READ_ONLY); tagCombo.setItems(new String[] { Tag.IGNORE.toString(), Tag.TIMESTAMP.toString(), Tag.EVENT_TYPE.toString(), Tag.MESSAGE.toString(), Tag.EXTRA_FIELD_NAME.toString(), Tag.EXTRA_FIELD_VALUE.toString(), Tag.OTHER.toString() }); tagCombo.setVisibleItemCount(tagCombo.getItemCount()); tagCombo.addSelectionListener(new SelectionListener() { @Override public void widgetDefaultSelected(SelectionEvent e) { } @Override public void widgetSelected(SelectionEvent e) { tagText.removeModifyListener(updateListener); switch (tagCombo.getSelectionIndex()) { case 0: // Ignore tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(false); break; case 1: // Time Stamp tagLabel.setText(Messages.CustomXmlParserInputWizardPage_format); tagLabel.setVisible(true); tagText.setVisible(true); tagText.addModifyListener(updateListener); actionCombo.setVisible(true); break; case 2: // Event type tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); break; case 3: // Message tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); break; case 4: // Field names tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(false); break; case 5: // Field values tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); break; case 6: // Other tagLabel.setText(Messages.CustomXmlParserInputWizardPage_name); tagLabel.setVisible(true); if (tagText.getText().trim().length() == 0) { tagText.setText(elementNameText.getText().trim()); } tagText.setVisible(true); tagText.addModifyListener(updateListener); actionCombo.setVisible(true); break; default: break; } tagComposite.layout(); validate(); updatePreviews(); } }); tagLabel = new Label(tagComposite, SWT.NULL); tagLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); tagText = new Text(tagComposite, SWT.BORDER | SWT.SINGLE); gd = new GridData(SWT.FILL, SWT.CENTER, true, false); gd.widthHint = 0; tagText.setLayoutData(gd); actionCombo = new Combo(tagComposite, SWT.DROP_DOWN | SWT.READ_ONLY); actionCombo.setItems(new String[] { Messages.CustomXmlParserInputWizardPage_set, Messages.CustomXmlParserInputWizardPage_append, Messages.CustomXmlParserInputWizardPage_appendWith }); actionCombo.select(inputElement.getInputAction()); actionCombo.addSelectionListener(updateListener); if (inputElement.getInputTag().equals(Tag.IGNORE)) { tagCombo.select(0); tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(false); } else if (inputElement.getInputTag().equals(Tag.TIMESTAMP)) { tagCombo.select(1); tagLabel.setText(Messages.CustomXmlParserInputWizardPage_format); tagText.setText(inputElement.getInputFormat()); tagText.addModifyListener(updateListener); actionCombo.setVisible(true); } else if (inputElement.getInputTag().equals(Tag.EVENT_TYPE)) { tagCombo.select(2); tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); } else if (inputElement.getInputTag().equals(Tag.MESSAGE)) { tagCombo.select(3); tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); } else if (inputElement.getInputTag().equals(Tag.EXTRA_FIELD_NAME)) { tagCombo.select(4); tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(false); } else if (inputElement.getInputTag().equals(Tag.EXTRA_FIELD_VALUE)) { tagCombo.select(5); tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); } else { tagCombo.select(6); tagLabel.setText(Messages.CustomXmlParserInputWizardPage_name); tagText.setText(inputElement.getInputName()); tagText.addModifyListener(updateListener); actionCombo.setVisible(true); } eventTypeButton = new Button(group, SWT.CHECK); eventTypeButton.setText(Messages.CustomTxtParserInputWizardPage_eventType); eventTypeButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); eventTypeButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (eventTypeButton.getSelection()) { eventTypeText.setEnabled(true); } else { eventTypeText.setEnabled(false); } } }); eventTypeButton.addSelectionListener(updateListener); eventTypeText = new Text(group, SWT.BORDER | SWT.SINGLE); gd = new GridData(SWT.FILL, SWT.CENTER, true, false); gd.widthHint = 0; eventTypeText.setLayoutData(gd); if (inputElement.getEventType() != null) { eventTypeText.setText(inputElement.getEventType()); eventTypeButton.setSelection(true); } else { eventTypeText.setEnabled(false); eventTypeButton.setSelection(false); } eventTypeText.addModifyListener(updateListener); } if (inputElement.getAttributes() != null) { for (CustomXmlInputAttribute inputAttribute : inputElement.getAttributes()) { Attribute attribute = new Attribute(group, this, inputAttribute, attributes.size() + 1); attributes.add(attribute); } } createAddButton(); } private void updatePreview() { Element element = getPreviewElement(inputElement); // no preview text for document element if (inputElement.getParentElement() != null) { previewText.setText(Messages.CustomXmlParserInputWizardPage_noMatchingElement); if (element != null) { previewText.setText(CustomXmlTrace.parseElement(element, new StringBuffer()).toString()); if (logEntryButton.getSelection()) { if (!logEntryFound) { logEntryFound = true; logEntriesCount++; } else { // remove nested log entry logEntryButton.setSelection(false); } } if (tagCombo.getText().equals(Tag.TIMESTAMP.toString()) && logEntriesCount <= 1) { String value = previewText.getText().trim(); if (value.length() != 0) { if (actionCombo.getSelectionIndex() == CustomTraceDefinition.ACTION_SET) { timeStampValue = value; timeStampFormat = tagText.getText().trim(); } else if (actionCombo.getSelectionIndex() == CustomTraceDefinition.ACTION_APPEND) { if (timeStampValue != null) { timeStampValue += value; timeStampFormat += tagText.getText().trim(); } else { timeStampValue = value; timeStampFormat = tagText.getText().trim(); } } else if (actionCombo.getSelectionIndex() == CustomTraceDefinition.ACTION_APPEND_WITH_SEPARATOR) { if (timeStampValue != null) { timeStampValue += CustomTraceDefinition.SEPARATOR + value; timeStampFormat += CustomTraceDefinition.SEPARATOR + tagText.getText().trim(); } else { timeStampValue = value; timeStampFormat = tagText.getText().trim(); } } } } } } for (Attribute attribute : attributes) { if (element != null) { String value = element.getAttribute(attribute.attributeNameText.getText().trim()); if (value.length() != 0) { attribute.previewText.setText(value); if (attribute.tagCombo.getText().equals(Tag.TIMESTAMP.toString()) && logEntriesCount <= 1) { if (attribute.actionCombo.getSelectionIndex() == CustomTraceDefinition.ACTION_SET) { timeStampValue = value; timeStampFormat = attribute.tagText.getText().trim(); } else if (attribute.actionCombo.getSelectionIndex() == CustomTraceDefinition.ACTION_APPEND) { if (timeStampValue != null) { timeStampValue += value; timeStampFormat += attribute.tagText.getText().trim(); } else { timeStampValue = value; timeStampFormat = attribute.tagText.getText().trim(); } } else if (attribute.actionCombo.getSelectionIndex() == CustomTraceDefinition.ACTION_APPEND_WITH_SEPARATOR) { if (timeStampValue != null) { timeStampValue += " | " + value; //$NON-NLS-1$ timeStampFormat += " | " + attribute.tagText.getText().trim(); //$NON-NLS-1$ } else { timeStampValue = value; timeStampFormat = attribute.tagText.getText().trim(); } } } } else { attribute.previewText.setText(Messages.CustomXmlParserInputWizardPage_noMatchingAttribute); } } else { attribute.previewText.setText(Messages.CustomXmlParserInputWizardPage_noMatchingElement); } } for (ElementNode child : childElements) { child.updatePreview(); } if (logEntryButton != null && logEntryButton.getSelection()) { logEntryFound = false; } } private void createAddButton() { fillerLabel = new Label(group, SWT.NONE); addAttributeComposite = new Composite(group, SWT.NONE); addAttributeComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); GridLayout addAttributeLayout = new GridLayout(2, false); addAttributeLayout.marginHeight = 0; addAttributeLayout.marginWidth = 0; addAttributeComposite.setLayout(addAttributeLayout); addAttributeButton = new Button(addAttributeComposite, SWT.PUSH); addAttributeButton.setImage(ADD_IMAGE); addAttributeButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_addAttribute); addAttributeButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { removeAddButton(); String attributeName = getAttributeNameSuggestion(inputElement); CustomXmlInputAttribute inputAttribute = new CustomXmlInputAttribute(attributeName, Tag.OTHER, attributeName, 0, ""); //$NON-NLS-1$ attributes.add(new Attribute(group, ElementNode.this, inputAttribute, attributes.size() + 1)); createAddButton(); elementContainer.layout(); elementScrolledComposite.setMinSize(elementContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).x, elementContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).y - 1); group.getParent().layout(); validate(); updatePreviews(); } }); addAttributeLabel = new Label(addAttributeComposite, SWT.NULL); addAttributeLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); addAttributeLabel.setText(Messages.CustomXmlParserInputWizardPage_newAttibute); } private void removeAddButton() { fillerLabel.dispose(); addAttributeComposite.dispose(); } private void removeAttribute(int attributeNumber) { int nb = attributeNumber; if (--nb < attributes.size()) { attributes.remove(nb).dispose(); for (int i = nb; i < attributes.size(); i++) { attributes.get(i).setAttributeNumber(i + 1); } elementContainer.layout(); elementScrolledComposite.setMinSize(elementContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).x, elementContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT).y - 1); group.getParent().layout(); } } private void dispose() { group.dispose(); } private void extractInputs() { inputElement.setElementName(elementNameText.getText().trim()); if (inputElement.getParentElement() != null) { inputElement.setLogEntry(logEntryButton.getSelection()); inputElement.setEventType(eventTypeButton.getSelection() ? eventTypeText.getText().trim() : null); Tag inputTag = Tag.fromLabel(tagCombo.getText()); inputElement.setInputTag(inputTag); if (inputTag.equals(Tag.OTHER)) { inputElement.setInputName(tagText.getText().trim()); } else { inputElement.setInputName(inputTag.toString()); if (inputTag.equals(Tag.TIMESTAMP)) { inputElement.setInputFormat(tagText.getText().trim()); } } inputElement.setInputAction(actionCombo.getSelectionIndex()); } inputElement.setAttributes(new ArrayList<CustomXmlInputAttribute>(attributes.size())); for (int i = 0; i < attributes.size(); i++) { String inputName = null; String inputFormat = null; Attribute attribute = attributes.get(i); String attributeName = attribute.attributeNameText.getText().trim(); Tag inputTag = Tag.fromLabel(attribute.tagCombo.getText()); if (inputTag.equals(Tag.OTHER)) { inputName = attribute.tagText.getText().trim(); } else { inputName = inputTag.toString(); if (inputTag.equals(Tag.TIMESTAMP)) { inputFormat = attribute.tagText.getText().trim(); } } int inputAction = attribute.actionCombo.getSelectionIndex(); inputElement.addAttribute(new CustomXmlInputAttribute(attributeName, inputTag, inputName, inputAction, inputFormat)); } } } private class Attribute { private ElementNode element; private int attributeNumber; // children of parent (must be disposed) private Composite labelComposite; private Composite attributeComposite; private Label filler; private Composite tagComposite; // children of labelComposite private Label attributeLabel; // children of attributeComposite private Text attributeNameText; private Text previewText; // children of tagComposite private Combo tagCombo; private Label tagLabel; private Text tagText; private Combo actionCombo; public Attribute(Composite parent, ElementNode element, CustomXmlInputAttribute inputAttribute, int attributeNumber) { this.element = element; this.attributeNumber = attributeNumber; labelComposite = new Composite(parent, SWT.FILL); GridLayout labelLayout = new GridLayout(2, false); labelLayout.marginWidth = 0; labelLayout.marginHeight = 0; labelComposite.setLayout(labelLayout); labelComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); Button deleteButton = new Button(labelComposite, SWT.PUSH); deleteButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); deleteButton.setImage(DELETE_IMAGE); deleteButton.setToolTipText(Messages.CustomXmlParserInputWizardPage_removeAttribute); deleteButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { Attribute.this.element.removeAttribute(Attribute.this.attributeNumber); validate(); updatePreviews(); } }); attributeLabel = new Label(labelComposite, SWT.NULL); attributeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); attributeLabel.setText(Messages.CustomXmlParserInputWizardPage_attibute); attributeComposite = new Composite(parent, SWT.FILL); GridLayout attributeLayout = new GridLayout(4, false); attributeLayout.marginWidth = 0; attributeLayout.marginHeight = 0; attributeComposite.setLayout(attributeLayout); attributeComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); Label nameLabel = new Label(attributeComposite, SWT.NONE); nameLabel.setText(Messages.CustomXmlParserInputWizardPage_name); attributeNameText = new Text(attributeComposite, SWT.BORDER | SWT.SINGLE); attributeNameText.setLayoutData(new GridData(120, SWT.DEFAULT)); attributeNameText.setText(inputAttribute.getAttributeName()); attributeNameText.addModifyListener(updateListener); Label previewLabel = new Label(attributeComposite, SWT.NONE); previewLabel.setText(Messages.CustomXmlParserInputWizardPage_preview); previewText = new Text(attributeComposite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY); GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false); gd.widthHint = 0; previewText.setLayoutData(gd); previewText.setText(Messages.CustomXmlParserInputWizardPage_noMatch); previewText.setBackground(COLOR_WIDGET_BACKGROUND); filler = new Label(parent, SWT.NULL); tagComposite = new Composite(parent, SWT.FILL); GridLayout tagLayout = new GridLayout(4, false); tagLayout.marginWidth = 0; tagLayout.marginHeight = 0; tagComposite.setLayout(tagLayout); tagComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); tagCombo = new Combo(tagComposite, SWT.DROP_DOWN | SWT.READ_ONLY); tagCombo.setItems(new String[] { Tag.TIMESTAMP.toString(), Tag.EVENT_TYPE.toString(), Tag.MESSAGE.toString(), Tag.EXTRA_FIELD_NAME.toString(), Tag.EXTRA_FIELD_VALUE.toString(), Tag.OTHER.toString() }); tagCombo.select(3); // Other tagCombo.addSelectionListener(new SelectionListener() { @Override public void widgetDefaultSelected(SelectionEvent e) { } @Override public void widgetSelected(SelectionEvent e) { tagText.removeModifyListener(updateListener); switch (tagCombo.getSelectionIndex()) { case 0: // Time Stamp tagLabel.setText(Messages.CustomXmlParserInputWizardPage_format); tagLabel.setVisible(true); tagText.setVisible(true); tagText.addModifyListener(updateListener); actionCombo.setVisible(true); break; case 1: // Event type tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); break; case 2: // Message tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); break; case 3: // Field names tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(false); break; case 4: // Field values tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); break; case 5: // Other tagLabel.setText(Messages.CustomXmlParserInputWizardPage_name); tagLabel.setVisible(true); if (tagText.getText().trim().length() == 0) { tagText.setText(attributeNameText.getText().trim()); } tagText.setVisible(true); tagText.addModifyListener(updateListener); actionCombo.setVisible(true); break; default: break; } tagComposite.layout(); validate(); updatePreviews(); } }); tagLabel = new Label(tagComposite, SWT.NULL); tagLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); tagText = new Text(tagComposite, SWT.BORDER | SWT.SINGLE); gd = new GridData(SWT.FILL, SWT.CENTER, true, false); gd.widthHint = 0; tagText.setLayoutData(gd); tagText.setText(attributeNameText.getText()); actionCombo = new Combo(tagComposite, SWT.DROP_DOWN | SWT.READ_ONLY); actionCombo.setItems(new String[] { Messages.CustomXmlParserInputWizardPage_set, Messages.CustomXmlParserInputWizardPage_append, Messages.CustomXmlParserInputWizardPage_appendWith }); actionCombo.select(inputAttribute.getInputAction()); actionCombo.addSelectionListener(updateListener); if (inputAttribute.getInputTag().equals(Tag.TIMESTAMP)) { tagCombo.select(0); tagLabel.setText(Messages.CustomXmlParserInputWizardPage_format); tagText.setText(inputAttribute.getInputFormat()); tagText.addModifyListener(updateListener); actionCombo.setVisible(true); } else if (inputAttribute.getInputTag().equals(Tag.EVENT_TYPE)) { tagCombo.select(1); tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); } else if (inputAttribute.getInputTag().equals(Tag.MESSAGE)) { tagCombo.select(2); tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); } else if (inputAttribute.getInputTag().equals(Tag.EXTRA_FIELD_NAME)) { tagCombo.select(3); tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(false); } else if (inputAttribute.getInputTag().equals(Tag.EXTRA_FIELD_VALUE)) { tagCombo.select(4); tagLabel.setVisible(false); tagText.setVisible(false); actionCombo.setVisible(true); } else { tagCombo.select(5); tagLabel.setText(Messages.CustomXmlParserInputWizardPage_name); tagText.setText(inputAttribute.getInputName()); tagText.addModifyListener(updateListener); actionCombo.setVisible(true); } } private void dispose() { labelComposite.dispose(); attributeComposite.dispose(); filler.dispose(); tagComposite.dispose(); } private void setAttributeNumber(int attributeNumber) { this.attributeNumber = attributeNumber; labelComposite.layout(); } } private Element getPreviewElement(CustomXmlInputElement inputElement) { CustomXmlInputElement currentElement = inputElement; Element element = documentElement; if (element != null) { if (!documentElement.getNodeName().equals(definition.rootInputElement.getElementName())) { return null; } ArrayList<String> elementNames = new ArrayList<>(); while (currentElement != null) { elementNames.add(currentElement.getElementName()); currentElement = currentElement.getParentElement(); } for (int i = elementNames.size() - 1; --i >= 0;) { NodeList childList = element.getChildNodes(); element = null; for (int j = 0; j < childList.getLength(); j++) { Node child = childList.item(j); if (child instanceof Element && child.getNodeName().equals(elementNames.get(i))) { element = (Element) child; break; } } if (element == null) { break; } } if (element != null) { return element; } } return null; } private String getChildNameSuggestion(CustomXmlInputElement inputElement) { if (inputElement == null) { if (documentElement != null) { return documentElement.getNodeName(); } } else { Element element = getPreviewElement(inputElement); if (element != null) { NodeList childNodes = element.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node node = childNodes.item(i); if (node instanceof Element) { boolean unused = true; if (inputElement.getChildElements() != null) { for (CustomXmlInputElement child : inputElement.getChildElements()) { if (child.getElementName().equals(node.getNodeName())) { unused = false; break; } } } if (unused) { return node.getNodeName(); } } } } } return ""; //$NON-NLS-1$ } private String getAttributeNameSuggestion(CustomXmlInputElement inputElement) { Element element = getPreviewElement(inputElement); if (element != null) { NamedNodeMap attributeMap = element.getAttributes(); for (int i = 0; i < attributeMap.getLength(); i++) { Node node = attributeMap.item(i); boolean unused = true; if (inputElement.getAttributes() != null) { for (CustomXmlInputAttribute attribute : inputElement.getAttributes()) { if (attribute.getAttributeName().equals(node.getNodeName())) { unused = false; break; } } } if (unused) { return node.getNodeName(); } } } return ""; //$NON-NLS-1$ } private void validate() { definition.categoryName = categoryText.getText().trim(); definition.definitionName = logtypeText.getText().trim(); definition.timeStampOutputFormat = timeStampOutputFormatText.getText().trim(); if (selectedElement != null) { selectedElement.extractInputs(); treeViewer.refresh(); } List<String> errors = new ArrayList<>(); if (definition.categoryName.length() == 0) { errors.add(Messages.CustomXmlParserInputWizardPage_emptyCategoryError); categoryText.setBackground(COLOR_LIGHT_RED); } else if (definition.definitionName.length() == 0) { errors.add(Messages.CustomXmlParserInputWizardPage_emptyLogTypeError); logtypeText.setBackground(COLOR_LIGHT_RED); } else { categoryText.setBackground(COLOR_TEXT_BACKGROUND); logtypeText.setBackground(COLOR_TEXT_BACKGROUND); if (definition.categoryName.indexOf(':') != -1) { errors.add(Messages.CustomXmlParserInputWizardPage_invalidCategoryError); categoryText.setBackground(COLOR_LIGHT_RED); } if (definition.definitionName.indexOf(':') != -1) { errors.add(Messages.CustomXmlParserInputWizardPage_invalidLogTypeError); logtypeText.setBackground(COLOR_LIGHT_RED); } for (TraceTypeHelper helper : TmfTraceType.getTraceTypeHelpers()) { if (definition.categoryName.equals(helper.getCategoryName()) && definition.definitionName.equals(helper.getName()) && (editDefinitionName == null || !editDefinitionName.equals(definition.definitionName)) && (editCategoryName == null || !editCategoryName.equals(definition.categoryName))) { errors.add(Messages.CustomXmlParserInputWizardPage_duplicatelogTypeError); logtypeText.setBackground(COLOR_LIGHT_RED); break; } } } if (definition.rootInputElement == null) { errors.add(Messages.CustomXmlParserInputWizardPage_noDocumentError); } if (definition.rootInputElement != null) { logEntryFound = false; timeStampFound = false; errors.addAll(validateElement(definition.rootInputElement)); if ((definition.rootInputElement.getAttributes() != null && definition.rootInputElement.getAttributes().size() != 0) || (definition.rootInputElement.getChildElements() != null && definition.rootInputElement.getChildElements().size() != 0) || errors.size() == 0) { if (!logEntryFound) { errors.add(Messages.CustomXmlParserInputWizardPage_missingLogEntryError); } if (timeStampFound && !definition.timeStampOutputFormat.isEmpty()) { try { new TmfTimestampFormat(timeStampOutputFormatText.getText().trim()); timeStampOutputFormatText.setBackground(COLOR_TEXT_BACKGROUND); } catch (IllegalArgumentException e) { errors.add(Messages.CustomXmlParserInputWizardPage_elementInvalidTimestampFmtError); timeStampOutputFormatText.setBackground(COLOR_LIGHT_RED); } } else { timeStampOutputFormatText.setBackground(COLOR_TEXT_BACKGROUND); if (!timeStampFound) { timeStampPreviewText.setText(Messages.CustomXmlParserInputWizardPage_noTimestampElementOrAttribute); } } } } else { timeStampPreviewText.setText(Messages.CustomXmlParserInputWizardPage_noTimestampElementOrAttribute); } if (errors.size() == 0) { setDescription(defaultDescription); setPageComplete(true); } else { setDescription(Joiner.on(' ').join(errors)); setPageComplete(false); } } /** * Clean up the specified XML element. * * @param inputElement * The element to clean up * @return The validated element */ public List<String> validateElement(CustomXmlInputElement inputElement) { List<String> errors = new ArrayList<>(); ElementNode elementNode = null; if (selectedElement != null && selectedElement.inputElement.equals(inputElement)) { elementNode = selectedElement; } if (inputElement == definition.rootInputElement) { if (inputElement.getElementName().length() == 0) { errors.add(Messages.CustomXmlParserInputWizardPage_missingDocumentElementError); if (elementNode != null) { elementNode.elementNameText.setBackground(COLOR_LIGHT_RED); } } else { if (elementNode != null) { elementNode.elementNameText.setBackground(COLOR_TEXT_BACKGROUND); } } } if (inputElement != definition.rootInputElement) { if (inputElement.isLogEntry()) { logEntryFound = true; } if (inputElement.getInputTag().equals(Tag.TIMESTAMP)) { timeStampFound = true; if (inputElement.getInputFormat().length() == 0) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementMissingTimestampFmtError, getName(inputElement))); if (elementNode != null) { elementNode.tagText.setBackground(COLOR_LIGHT_RED); } } else { try { new TmfTimestampFormat(inputElement.getInputFormat()); if (elementNode != null) { elementNode.tagText.setBackground(COLOR_TEXT_BACKGROUND); } } catch (IllegalArgumentException e) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementInvalidTimestampFmtError, getName(inputElement))); if (elementNode != null) { elementNode.tagText.setBackground(COLOR_LIGHT_RED); } } } } else if (inputElement.getInputName().length() == 0) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementMissingInputNameError, getName(inputElement))); if (elementNode != null) { elementNode.tagText.setBackground(COLOR_LIGHT_RED); } } else if (inputElement.getInputTag().equals(Tag.OTHER) && Tag.fromLabel(inputElement.getInputName()) != null) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementReservedInputNameError, getName(inputElement))); if (elementNode != null) { elementNode.tagText.setBackground(COLOR_LIGHT_RED); } } else { if (elementNode != null) { elementNode.tagText.setBackground(COLOR_TEXT_BACKGROUND); } } if (inputElement.getEventType() != null && inputElement.getEventType().trim().isEmpty()) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_emptyEventTypeError, getName(inputElement))); if (elementNode != null) { elementNode.eventTypeText.setBackground(COLOR_LIGHT_RED); } } else { if (elementNode != null) { elementNode.eventTypeText.setBackground(COLOR_TEXT_BACKGROUND); } } } if (inputElement.getAttributes() != null) { if (elementNode != null) { for (Attribute attribute : elementNode.attributes) { attribute.attributeNameText.setBackground(COLOR_TEXT_BACKGROUND); } } for (int i = 0; i < inputElement.getAttributes().size(); i++) { CustomXmlInputAttribute attribute = inputElement.getAttributes().get(i); boolean duplicate = false; for (int j = i + 1; j < inputElement.getAttributes().size(); j++) { CustomXmlInputAttribute otherAttribute = inputElement.getAttributes().get(j); if (otherAttribute.getAttributeName().equals(attribute.getAttributeName())) { duplicate = true; if (elementNode != null) { elementNode.attributes.get(j).attributeNameText.setBackground(COLOR_LIGHT_RED); } } } if (attribute.getAttributeName().length() == 0) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeMissingNameError, getName(inputElement))); if (elementNode != null) { elementNode.attributes.get(i).attributeNameText.setBackground(COLOR_LIGHT_RED); } } else if (duplicate) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeDuplicateNameError, getName(attribute, inputElement))); if (elementNode != null) { elementNode.attributes.get(i).attributeNameText.setBackground(COLOR_LIGHT_RED); } } if (attribute.getInputTag().equals(Tag.TIMESTAMP)) { timeStampFound = true; if (attribute.getInputFormat().length() == 0) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeMissingTimestampFmtError, getName(attribute, inputElement))); if (elementNode != null) { elementNode.attributes.get(i).tagText.setBackground(COLOR_LIGHT_RED); } } else { try { new TmfTimestampFormat(attribute.getInputFormat()); if (elementNode != null) { elementNode.attributes.get(i).tagText.setBackground(COLOR_TEXT_BACKGROUND); } } catch (IllegalArgumentException e) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeInvalidTimestampFmtError, getName(attribute, inputElement))); if (elementNode != null) { elementNode.attributes.get(i).tagText.setBackground(COLOR_LIGHT_RED); } } } } else if (attribute.getInputName().length() == 0) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeMissingInputNameError, getName(attribute, inputElement))); if (elementNode != null) { elementNode.attributes.get(i).tagText.setBackground(COLOR_LIGHT_RED); } } else if (attribute.getInputTag().equals(Tag.OTHER) && Tag.fromLabel(attribute.getInputName()) != null) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeReservedInputNameError, getName(attribute, inputElement))); if (elementNode != null) { elementNode.attributes.get(i).tagText.setBackground(COLOR_LIGHT_RED); } } else { if (elementNode != null) { elementNode.attributes.get(i).tagText.setBackground(COLOR_TEXT_BACKGROUND); } } } } if (inputElement.getChildElements() != null) { for (CustomXmlInputElement child : inputElement.getChildElements()) { ElementNode childElementNode = null; if (selectedElement != null && selectedElement.inputElement.equals(child)) { childElementNode = selectedElement; } if (childElementNode != null) { childElementNode.elementNameText.setBackground(COLOR_TEXT_BACKGROUND); } } for (int i = 0; i < inputElement.getChildElements().size(); i++) { CustomXmlInputElement child = inputElement.getChildElements().get(i); ElementNode childElementNode = null; if (selectedElement != null && selectedElement.inputElement.equals(child)) { childElementNode = selectedElement; } if (child.getElementName().length() == 0) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementMissingNameError, getName(child))); if (childElementNode != null) { childElementNode.elementNameText.setBackground(COLOR_LIGHT_RED); } } else { boolean duplicate = false; for (int j = i + 1; j < inputElement.getChildElements().size(); j++) { CustomXmlInputElement otherChild = inputElement.getChildElements().get(j); if (otherChild.getElementName().equals(child.getElementName())) { duplicate = true; ElementNode otherChildElementNode = null; if (selectedElement != null && selectedElement.inputElement.equals(otherChild)) { otherChildElementNode = selectedElement; } if (otherChildElementNode != null) { otherChildElementNode.elementNameText.setBackground(COLOR_LIGHT_RED); } } } if (duplicate) { errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementDuplicateNameError, getName(child))); if (childElementNode != null) { childElementNode.elementNameText.setBackground(COLOR_LIGHT_RED); } } } errors.addAll(validateElement(child)); } } return errors; } /** * Get the trace definition. * * @return The trace definition */ public CustomXmlTraceDefinition getDefinition() { return definition; } /** * Get the raw text input. * * @return The raw text input. */ public char[] getInputText() { return inputText.getText().toCharArray(); } }