com.windowtester.eclipse.ui.convert.WTConvertAPIRefactoring.java Source code

Java tutorial

Introduction

Here is the source code for com.windowtester.eclipse.ui.convert.WTConvertAPIRefactoring.java

Source

/*******************************************************************************
 *  Copyright (c) 2012 Google, Inc.
 *  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:
 *  Google, Inc. - initial API and implementation
 *******************************************************************************/
package com.windowtester.eclipse.ui.convert;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.text.edits.ReplaceEdit;

import com.windowtester.eclipse.ui.convert.rule.WTReplaceIUIContextMethodCallWithEnsureThatRule;
import com.windowtester.eclipse.ui.convert.rule.WTReplacePauseCallsRule;
import com.windowtester.eclipse.ui.convert.rule.WTReplaceSWTWidgetLocatorRule;
import com.windowtester.eclipse.ui.convert.rule.WTReplaceTypeRule;
import com.windowtester.runtime.locator.IWidgetReference;
import com.windowtester.runtime.swing.UITestCaseSwing;
import com.windowtester.runtime.swt.UITestCaseSWT;
import com.windowtester.runtime.swt.UnableToFindActiveShellException;
import com.windowtester.runtime.swt.locator.ShellLocator;
import com.windowtester.runtime.swt.locator.eclipse.ActiveEditorLocator;
import com.windowtester.runtime.swt.util.DebugHelper;

/**
 * Refactoring for converting/migrating all java code in the selection
 * project/package/class to use the new WindowTester API.
 */
public class WTConvertAPIRefactoring extends Refactoring {
    private final List<IJavaElement> selection;
    private WTConvertAPIRule[] rules;
    private Collection<IJavaElement> visited = new HashSet<IJavaElement>();
    private CompositeChange compositeChange;
    private RefactoringStatus status;

    public WTConvertAPIRefactoring(List<IJavaElement> selected) {
        this.selection = selected;
    }

    public String getName() {
        return "WindowTester API Conversion";
    }

    /**
     * Set the rules used to convert WindowTester API. This is used for testing purposes,
     * and need not be called during normal operation.
     * 
     * @param rules an array of conversion rules (not <code>null</code>, contains no
     *            <code>null</code>s)
     */
    public void setRules(WTConvertAPIRule[] rules) {
        this.rules = rules;
    }

    /**
     * Answer the rules used to convert WindowTester API. This is used for testing
     * purposes, and need not be called during normal operation.
     * 
     * @re rules an array of conversion rules (not <code>null</code>, contains no
     *     <code>null</code>s)
     */
    public WTConvertAPIRule[] getRules() {
        if (rules == null) {
            rules = new WTConvertAPIRule[] {

                    // TODO Include all old API WT classes that need to be replaced one-for-one with new API WT classes
                    new WTReplaceTypeRule("com.windowtester.runtime.swt.experimental.locator.ActiveEditorLocator",
                            ActiveEditorLocator.class),
                    new WTReplaceTypeRule("com.windowtester.swt.util.DebugHelper", DebugHelper.class),
                    new WTReplaceTypeRule("com.windowtester.runtime.locator.WidgetReference",
                            IWidgetReference.class),
                    new WTReplaceTypeRule("junit.extensions.UITestCase", UITestCaseSWT.class),
                    new WTReplaceTypeRule("junit.extensions.UITestCaseSWT", UITestCaseSWT.class),
                    new WTReplaceTypeRule("junit.extensions.UITestCaseSwing", UITestCaseSwing.class),
                    new WTReplaceTypeRule("com.windowtester.runtime.swt.finder.UnableToFindActiveShellException",
                            UnableToFindActiveShellException.class),

                    // ??? Should we be converting references to internal classes ??? 
                    new WTReplaceTypeRule("com.windowtester.swt.util.ExceptionHandlingHelper",
                            "com.windowtester.runtime.swt.internal.ExceptionHandlingHelper"),
                    new WTReplaceTypeRule("com.windowtester.event.swt.text.InsertTextEntryStrategy",
                            "com.windowtester.runtime.swt.internal.text.InsertTextEntryStrategy"),
                    new WTReplaceTypeRule("com.windowtester.event.swt.text.ITextEntryStrategy",
                            "com.windowtester.runtime.swt.internal.text.ITextEntryStrategy"),
                    new WTReplaceTypeRule("com.windowtester.event.swt.text.TextEntryStrategy",
                            "com.windowtester.runtime.swt.internal.text.TextEntryStrategy"),
                    new WTReplaceTypeRule("com.windowtester.swt.util.PathStringTokenizerUtil",
                            "com.windowtester.runtime.swt.internal.util.PathStringTokenizerUtil"),
                    new WTReplaceTypeRule("com.windowtester.swt.util.TextUtils",
                            "com.windowtester.runtime.swt.internal.util.TextUtils"),
                    new WTReplaceTypeRule("com.windowtester.swt.WidgetLocatorService",
                            "com.windowtester.runtime.swt.internal.finder.WidgetLocatorService"),
                    new WTReplaceTypeRule("com.windowtester.finder.swt.ShellFinder",
                            "com.windowtester.runtime.swt.internal.finder.ShellFinder"),

                    // TODO Include all constructor replacement rules
                    new WTReplaceSWTWidgetLocatorRule(Shell.class, ShellLocator.class),

                    // TODO Include all method call replacement rules
                    new WTReplaceIUIContextMethodCallWithEnsureThatRule("setFocus", "hasFocus"),
                    new WTReplaceIUIContextMethodCallWithEnsureThatRule("close", "isClosed"),
                    new WTReplacePauseCallsRule() };
        }
        return rules;
    }

    /**
     * Checks some initial conditions based on the element to be refactored. The method is
     * typically called by the UI to perform an initial checks after an action has been
     * executed.
     * <p>
     * The refactoring has to be considered as not being executable if the returned status
     * has the severity of <code>RefactoringStatus#FATAL</code>.
     */
    public RefactoringStatus checkInitialConditions(IProgressMonitor monitor)
            throws CoreException, OperationCanceledException {
        if (monitor != null) {
            monitor.beginTask("", 1); //$NON-NLS-1$
            monitor.worked(1);
            monitor.done();
        }
        return new RefactoringStatus();
    }

    /**
     * After <code>checkInitialConditions</code> has been performed and the user has
     * provided all input necessary to perform the refactoring this method is called to
     * check the remaining preconditions.
     * <p>
     * The refactoring has to be considered as not being executable if the returned status
     * has the severity of <code>RefactoringStatus#FATAL</code>.
     */
    public RefactoringStatus checkFinalConditions(IProgressMonitor monitor)
            throws CoreException, OperationCanceledException {
        if (monitor == null)
            monitor = new NullProgressMonitor();
        status = new RefactoringStatus();
        compositeChange = new CompositeChange("Convert to new WindowTester API");
        monitor.beginTask("Converting to new WindowTester API", selection.size());
        for (Iterator<IJavaElement> iter = selection.iterator(); iter.hasNext();)
            convertElement(iter.next(), new SubProgressMonitor(monitor, 1));
        monitor.done();

        //      if (monitor != null) {
        //         monitor.beginTask("", 1); //$NON-NLS-1$
        //         monitor.worked(1);
        //         monitor.done();
        //      }
        //
        //
        //      monitor.beginTask("Checking preconditions", selection.size());
        //      for (IJavaElement elem : selection) {
        //         checkForProblems(elem, status, monitor);
        //      }
        //      monitor.done();

        return status;
    }

    //   private void checkForProblems(IJavaElement elem, RefactoringStatus status, IProgressMonitor monitor)
    //      throws JavaModelException
    //   {
    //      switch (elem.getElementType()) {
    //         case IJavaElement.JAVA_PROJECT :
    //            IJavaProject project = (IJavaProject) elem;
    //            IPackageFragmentRoot[] roots = project.getPackageFragmentRoots();
    //            monitor.beginTask("Checking " + project.getPath(), roots.length);
    //            for (int i = 0; i < roots.length; i++)
    //               checkForProblems(roots[i], status, new SubProgressMonitor(monitor, 1));
    //            monitor.done();
    //            break;
    //         case IJavaElement.PACKAGE_FRAGMENT_ROOT :
    //            IPackageFragmentRoot root = (IPackageFragmentRoot) elem;
    //            IJavaElement[] children = root.getChildren();
    //            monitor.beginTask("Checking " + root.getPath(), children.length);
    //            for (int i = 0; i < children.length; i++)
    //               checkForProblems(children[i], status, new SubProgressMonitor(monitor, 1));
    //            monitor.done();
    //            break;
    //         case IJavaElement.PACKAGE_FRAGMENT :
    //            IPackageFragment pkg = (IPackageFragment) elem;
    //            monitor.beginTask("Converting " + pkg.getPath(), pkg.getChildren().length);
    //            for (IJavaElement child : pkg.getChildren())
    //               checkForProblems(child, status, new SubProgressMonitor(monitor, 1));
    //            monitor.done();
    //            break;
    //         case IJavaElement.COMPILATION_UNIT :
    //            ICompilationUnit cu = (ICompilationUnit) elem;
    //            if (hasProblem(cu)) {
    //               //JDT status contexts are all internal so this is the best we can do
    //               status.addWarning(cu.getElementName() + " has syntax errors and will be skipped");
    //            }
    //            break;
    //         default :
    //            break;
    //      }
    //   }

    //   private boolean hasProblem(ICompilationUnit cu) throws JavaModelException {
    //      String source = cu.getSource();
    //      ASTParser parser = ASTParser.newParser(AST.JLS3);
    //      parser.setSource(source.toCharArray());
    //      CompilationUnit compUnit = (CompilationUnit) parser.createAST(new NullProgressMonitor());
    //      IProblem[] problems = compUnit.getProblems();
    //      for (IProblem problem : problems) {
    //         if (problem.isError())
    //            return true;
    //      }
    //      return false;
    //   }

    /**
     * Recursively iterate over the selected java elements and their children to convert
     * each compilation to use the new WindowTester API. Creates a {@link Change} object
     * that performs the actual workspace transformation.
     */
    public Change createChange(IProgressMonitor monitor) throws CoreException, OperationCanceledException {
        return compositeChange;
    }

    /**
     * Recursively iterate over the specified java element and their children to convert
     * each compilation to use the new WindowTester API.
     * 
     * @param elem the java element (not <code>null</code>)
     * @param monitor the progress monitor (not <code>null</code>)
     */
    private void convertElement(IJavaElement elem, IProgressMonitor monitor) throws JavaModelException {
        switch (elem.getElementType()) {
        case IJavaElement.JAVA_PROJECT:
            convertProject((IJavaProject) elem, monitor);
            break;
        case IJavaElement.PACKAGE_FRAGMENT_ROOT:
            convertPackageRoot((IPackageFragmentRoot) elem, monitor);
            break;
        case IJavaElement.PACKAGE_FRAGMENT:
            convertPackage((IPackageFragment) elem, monitor);
            break;
        case IJavaElement.COMPILATION_UNIT:
            convertCompilationUnit((ICompilationUnit) elem, monitor);
            break;
        default:
            break;
        }
    }

    /**
     * Recursively iterate over the elements in the specified java element to convert each
     * compilation to use the new WindowTester API.
     * 
     * @param proj the java project (not <code>null</code>)
     * @param monitor the progress monitor (not <code>null</code>)
     */
    private void convertProject(IJavaProject proj, IProgressMonitor monitor) throws JavaModelException {
        if (visited.contains(proj))
            return;
        visited.add(proj);
        IPackageFragmentRoot[] roots = proj.getPackageFragmentRoots();
        monitor.beginTask("Converting " + proj.getPath(), roots.length);
        for (int i = 0; i < roots.length; i++)
            convertPackageRoot(roots[i], new SubProgressMonitor(monitor, 1));
        monitor.done();
    }

    /**
     * Recursively iterate over the elements in the specified java element to convert each
     * compilation to use the new WindowTester API.
     * 
     * @param root the package fragment root (not <code>null</code>)
     * @param monitor the progress monitor (not <code>null</code>)
     */
    private void convertPackageRoot(IPackageFragmentRoot root, IProgressMonitor monitor) throws JavaModelException {
        if (root.getKind() != IPackageFragmentRoot.K_SOURCE || visited.contains(root))
            return;
        visited.add(root);
        IJavaElement[] children = root.getChildren();
        monitor.beginTask("Converting " + root.getPath(), children.length);
        for (int i = 0; i < children.length; i++)
            convertElement(children[i], new SubProgressMonitor(monitor, 1));
        monitor.done();
    }

    /**
     * Recursively iterate over the elements in the specified java element to convert each
     * compilation to use the new WindowTester API.
     * 
     * @param pkg the package fragment (not <code>null</code>)
     * @param monitor the progress monitor (not <code>null</code>)
     */
    private void convertPackage(IPackageFragment pkg, IProgressMonitor monitor) throws JavaModelException {
        if (visited.contains(pkg))
            return;
        visited.add(pkg);
        IJavaElement[] children = pkg.getChildren();
        monitor.beginTask("Converting " + pkg.getPath(), children.length);
        for (int i = 0; i < children.length; i++)
            convertElement(children[i], new SubProgressMonitor(monitor, 1));
        monitor.done();
    }

    /**
     * Convert the specified compilation unit to use the new WindowTester API.
     * 
     * @param compUnit the compilation unit (not <code>null</code>)
     * @param monitor the progress monitor (not <code>null</code>)
     */
    private void convertCompilationUnit(ICompilationUnit compUnit, IProgressMonitor monitor)
            throws JavaModelException {
        if (visited.contains(compUnit))
            return;
        visited.add(compUnit);
        monitor.beginTask("Converting " + compUnit.getPath(), 1);
        String oldSource = compUnit.getSource();
        WTConvertAPIContext context;
        try {
            context = new WTConvertAPIContextBuilder().buildContext(compUnit);
            convertCompilationUnitSource(context);
        } catch (WTConvertAPIParseException e) {
            IProblem problem = e.getProblem();
            status.addWarning(compUnit.getElementName() + " has a syntax error on line "
                    + problem.getSourceLineNumber() + " and will be skipped: " + problem);
            return;
        }
        if (context.isSourceModified()) {
            String newSource = context.getSource();
            TextFileChange change = new TextFileChange(compUnit.getElementName(), (IFile) compUnit.getResource());
            change.setEdit(new ReplaceEdit(0, oldSource.length(), newSource));
            compositeChange.add(change);
        }
        monitor.done();
    }

    /**
     * Convert the specified compilation unit's source. This is used for testing purposes
     * and typically not called outside this class during the normal course of events
     * 
     * @param source the compilation unit source
     * @return the context containing the converted source (not <code>null</code>)
     */
    public WTConvertAPIContext convertCompilationUnitSource(String source) {
        WTConvertAPIContext context = new WTConvertAPIContextBuilder().buildContext(source);
        convertCompilationUnitSource(context);
        return context;
    }

    private void convertCompilationUnitSource(WTConvertAPIContext context) {
        if (context.hasWTReferences())
            for (WTConvertAPIRule rule : getRules())
                rule.convert(context);
    }
}