net.bpelunit.toolsupport.editors.BPELUnitEditor.java Source code

Java tutorial

Introduction

Here is the source code for net.bpelunit.toolsupport.editors.BPELUnitEditor.java

Source

/**
 * This file belongs to the BPELUnit utility and Eclipse plugin set. See enclosed
 * license file for more information.
 * 
 */
package net.bpelunit.toolsupport.editors;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.wsdl.Definition;
import javax.wsdl.WSDLException;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.xml.transform.TransformerException;

import net.bpelunit.framework.control.util.BPELUnitUtil;
import net.bpelunit.framework.xml.suite.XMLDeploymentSection;
import net.bpelunit.framework.xml.suite.XMLPartnerDeploymentInformation;
import net.bpelunit.framework.xml.suite.XMLPartnerTrack;
import net.bpelunit.framework.xml.suite.XMLTestSuite;
import net.bpelunit.framework.xml.suite.XMLTestSuiteDocument;
import net.bpelunit.framework.xml.suite.XMLTrack;
import net.bpelunit.toolsupport.ToolSupportActivator;
import net.bpelunit.toolsupport.editors.src.XMLEditor;
import net.bpelunit.toolsupport.util.WSDLReadingException;
import net.bpelunit.toolsupport.util.schema.WSDLParser;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.IDocument;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.forms.IFormPart;
import org.eclipse.ui.forms.editor.FormEditor;
import org.xml.sax.SAXException;

/**
 * The BPELUnit Editor.
 * 
 * @version $Id$
 * @author Philip Mayer
 * 
 */
public class BPELUnitEditor extends FormEditor {

    private static final int VISUAL_PAGE = 0;
    private static final int SOURCE_PAGE = 1;

    /**
     * The base model document for the test suite
     */
    private XMLTestSuiteDocument fDocument;

    /**
     * The first page of the editor (visual page)
     */
    private TestSuitePage fTestSuitePage;
    /**
     * The second page of the editor (source page)
     */
    private XMLEditor fXmlEditorPage;

    /**
     * Listeners on model changes
     */
    private List<IModelChangedListener> fListeners;

    /**
     * The project we're in
     */
    private IProject fCurrentProject;

    /**
     * The directory the .bpts is in
     */
    private IContainer fCurrentDirectory;

    /**
     * Cached WSDL definitions
     */
    private Map<IFile, Definition> fWSDLDefinitions;

    /**
     * Cached WSDL Parser
     */
    private Map<Definition, WSDLParser> fWSDLParser;

    /**
     * The page to be opened first (may change if parsing errors occur)
     */
    private int fFirstPage;

    // ***************** General editor methods *******************

    public BPELUnitEditor() {
        super();
        this.fListeners = new ArrayList<IModelChangedListener>();
    }

    @Override
    public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException {

        if (!(editorInput instanceof IFileEditorInput)) {
            throw new PartInitException("Invalid Input: Must be IFileEditorInput");
        }

        IFile baseFile = ((IFileEditorInput) editorInput).getFile();

        this.fCurrentProject = baseFile.getProject();
        this.fCurrentDirectory = baseFile.getParent();

        this.fWSDLDefinitions = new HashMap<IFile, Definition>();
        this.fWSDLParser = new HashMap<Definition, WSDLParser>();

        this.setPartName(baseFile.getName());

        if (!baseFile.exists()) {
            throw new PartInitException("Invalid Input: File " + baseFile + " does not exist.");
        }

        try {
            // Try to parse from a file whenever possible, so we may have access to the path
            // where it is stored. This could be important for editing fields which contain
            // relative paths from the .bpts file.
            final IPath rawLocation = baseFile.getRawLocation();
            if (rawLocation != null) {
                final File file = rawLocation.makeAbsolute().toFile();
                this.fDocument = XMLTestSuiteDocument.Factory.parse(file);
            } else {
                this.fDocument = XMLTestSuiteDocument.Factory
                        .parse(new InputStreamReader(baseFile.getContents(), baseFile.getCharset()));
            }
            if (this.needsBasicRestructuring(this.fDocument)) {
                this.fTestSuitePage.markDirty();
            }
            this.fFirstPage = VISUAL_PAGE;
        } catch (Exception e) {
            // Parsing not possible - switch to source view
            this.fFirstPage = SOURCE_PAGE;
        }

        super.init(site, editorInput);
    }

    @Override
    protected void addPages() {

        try {
            this.fTestSuitePage = new TestSuitePage(this, "testSuitePage", "Test Suite");
            this.addPage(this.fTestSuitePage);
            this.fXmlEditorPage = new XMLEditor();
            int index = this.addPage(this.fXmlEditorPage, this.getEditorInput());
            this.setPageText(index, "Source");

            /*
             * Set the first page (must be source if non-parseable)
             */
            this.setActivePage(this.fFirstPage);

        } catch (PartInitException e) {
            ToolSupportActivator.log(e);
        }
    }

    /**
     * The <code>MultiPageEditorPart</code> implementation of this
     * <code>IWorkbenchPart</code> method disposes all nested editors.
     * Subclasses may extend.
     */
    @Override
    public void dispose() {
        super.dispose();
    }

    @Override
    public void doSave(IProgressMonitor monitor) {

        this.preSave();
        // use the editor to save it
        this.fXmlEditorPage.doSave(monitor);
        this.postSave();

        super.editorDirtyStateChanged();
    }

    @Override
    public void doSaveAs() {
        this.preSave();

        this.fXmlEditorPage.doSaveAs();
        this.setInput(this.fXmlEditorPage.getEditorInput());

        this.postSave();
    }

    /*
     * (non-Javadoc) Method declared on IEditorPart.
     */
    @Override
    public boolean isSaveAsAllowed() {
        return true;
    }

    @Override
    protected void pageChange(int newPageIndex) {

        boolean canChange = true;

        if (newPageIndex == SOURCE_PAGE) {
            this.model2src(false);
        }
        if (newPageIndex == VISUAL_PAGE) {
            canChange = this.src2model(false);
        }
        if (canChange) {
            super.pageChange(newPageIndex);
        } else {
            this.setActivePage(SOURCE_PAGE);
        }
    }

    private void postSave() {
        if (this.getCurrentPage() == SOURCE_PAGE) {
            // refresh model (forced)
            this.src2model(true);
        }
    }

    private void preSave() {
        if (this.getCurrentPage() == VISUAL_PAGE) {
            // flushes data back into the model
            this.fTestSuitePage.doSave(new NullProgressMonitor());
            // copy data from model to text editor
            this.model2src(true);
        }
    }

    public XMLTestSuite getTestSuite() {
        XMLTestSuite testSuite = this.fDocument.getTestSuite();
        if (testSuite == null) {
            testSuite = this.fDocument.addNewTestSuite();
        }
        return testSuite;
    }

    private boolean src2model(boolean force) {
        /*
         * Grab if forced, if dirty, or if called for the first time
         */
        if (force || this.isDirty() || this.fDocument == null) {

            IDocument document = this.fXmlEditorPage.getDocumentProvider().getDocument(this.getEditorInput());
            String string = document.get();
            try {
                this.fDocument = XMLTestSuiteDocument.Factory.parse(string);
                if (this.needsBasicRestructuring(this.fDocument)) {
                    this.fTestSuitePage.markDirty();
                }

                for (IModelChangedListener listener : this.fListeners) {
                    listener.modelChanged();
                }
            } catch (Exception e) {
                ErrorDialog.openError(this.getShell(), "Trouble parsing XML", e.getMessage(),
                        ToolSupportActivator.getErrorStatus(e));
                return false;
            }
        }

        return true;
    }

    /**
     * Creates the basic elements if not already present.
     * 
     * @param document
     */
    private boolean needsBasicRestructuring(XMLTestSuiteDocument document) {
        boolean changed = false;

        if (document.getTestSuite() == null) {
            document.addNewTestSuite();
            changed = true;
        }

        XMLTestSuite suite = document.getTestSuite();

        if (suite.getDeployment() == null) {
            suite.addNewDeployment();
            changed = true;
        }
        if (suite.getTestCases() == null) {
            suite.addNewTestCases();
            changed = true;
        }

        XMLDeploymentSection deployment = suite.getDeployment();
        if (deployment.getPut() == null) {
            deployment.addNewPut();
            changed = true;
        }

        return changed;
    }

    private Shell getShell() {
        return this.fXmlEditorPage.getSite().getShell();
    }

    private void model2src(boolean force) {
        if ((force || this.isDirty()) && (this.fDocument != null)) {
            IDocument document = this.fXmlEditorPage.getDocumentProvider().getDocument(this.getEditorInput());
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            try {
                this.fDocument.save(output, BPELUnitUtil.getDefaultXMLOptions());
                document.set(output.toString());
            } catch (IOException e) {
                ErrorDialog.openError(this.getShell(), "Error", "Error writing XML model to file",
                        ToolSupportActivator.getErrorStatus(e));
            }
        }
    }

    public IProject getCurrentProject() {
        return this.fCurrentProject;
    }

    public IContainer getCurrentDirectory() {
        return this.fCurrentDirectory;
    }

    private String getPartnerWSDLString(XMLTrack track) {

        if (track instanceof XMLPartnerTrack) {
            XMLPartnerTrack partner = (XMLPartnerTrack) track;
            List<XMLPartnerDeploymentInformation> partnerList = this.getTestSuite().getDeployment()
                    .getPartnerList();
            for (XMLPartnerDeploymentInformation information : partnerList) {
                if (information.getName().equals(partner.getName())) {
                    return information.getPartnerWsdl();
                }
            }
        } else {
            return this.getTestSuite().getDeployment().getPut().getPartnerWSDL();
        }

        return null;
    }

    private String getWSDLString(XMLTrack track) {

        if (track instanceof XMLPartnerTrack) {
            XMLPartnerTrack partner = (XMLPartnerTrack) track;
            List<XMLPartnerDeploymentInformation> partnerList = this.getTestSuite().getDeployment()
                    .getPartnerList();
            for (XMLPartnerDeploymentInformation information : partnerList) {
                if (information.getName().equals(partner.getName())) {
                    return information.getWsdl();
                }
            }
        } else {
            return this.getTestSuite().getDeployment().getPut().getWsdl();
        }

        return null;
    }

    public Definition getWsdlForPartner(XMLTrack track) throws WSDLReadingException {

        String wsdl = this.getWSDLString(track);
        if (wsdl == null || "".equals(wsdl)) {
            return null;
        }

        return this.getWsdlForFile(wsdl);
    }

    public Definition getPartnerWsdlForPartner(XMLTrack track) throws WSDLReadingException {

        String wsdl = this.getPartnerWSDLString(track);
        if (wsdl == null || "".equals(wsdl)) {
            return null;
        }

        return this.getWsdlForFile(wsdl);
    }

    public Definition getWsdlForFile(String wsdl) throws WSDLReadingException {

        IPath path = new Path(wsdl);
        IResource resource = null;

        // try to find from current dir:
        resource = this.getCurrentDirectory().findMember(wsdl);

        // try to find from project dir:
        if (this.notFound(resource)) {
            resource = this.getCurrentProject().findMember(path);
        }

        if (this.notFound(resource)) {
            resource = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
        }

        // all hope failed...
        if (this.notFound(resource)) {
            throw new WSDLReadingException("Cannot find WSDL file with file path " + wsdl);
        }

        IFile file = (IFile) resource;

        // TODO caching probably NOT a good idea at all.
        Definition definition = this.fWSDLDefinitions.get(file);

        if (definition == null) {
            String fileName = file.getRawLocation().toFile().toString();
            // load WSDL
            try {
                WSDLFactory factory = WSDLFactory.newInstance();
                WSDLReader reader = factory.newWSDLReader();
                // reader.setFeature(Constants.FEATURE_VERBOSE, false);

                definition = reader.readWSDL(null, fileName);
                this.fWSDLDefinitions.put(file, definition);

                WSDLParser parser = new WSDLParser(definition);
                this.fWSDLParser.put(definition, parser);

            } catch (WSDLException e) {
                throw new WSDLReadingException("Error loading WSDL file for partner", e);
            } catch (SAXException e) {
                MessageDialog dialog = new MessageDialog(this.getShell(), "Invalid Schema", null, e.getMessage(),
                        MessageDialog.ERROR, new String[] { "OK" }, 0);
                dialog.open();
                throw new WSDLReadingException("Error reading Schemata in WSDL: " + e.getMessage(), e);
            } catch (TransformerException e) {
                MessageDialog dialog = new MessageDialog(this.getShell(), "Invalid Schema", null, e.getMessage(),
                        MessageDialog.ERROR, new String[] { "OK" }, 0);
                dialog.open();
                throw new WSDLReadingException("Error reading Schemata in WSDL: " + e.getMessage(), e);
            }
        }
        return definition;

    }

    public WSDLParser getWSDLParserForDefinition(Definition definition) {
        return this.fWSDLParser.get(definition);
    }

    private boolean notFound(IResource resource) {
        return (resource == null || !resource.exists() || !(resource instanceof IFile));
    }

    public void addModelChangedListener(IModelChangedListener listener) {
        this.fListeners.add(listener);
    }

    public void removeModelChangedListener(IModelChangedListener listener) {
        this.fListeners.remove(listener);
    }

    public void refresh() {
        if (getActivePage() == VISUAL_PAGE) {
            for (IFormPart part : fTestSuitePage.getManagedForm().getParts()) {
                part.refresh();
            }
        }

    }
}