com.google.gwt.eclipse.devtoolsgen.actions.PopulateGwtDevTools.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.eclipse.devtoolsgen.actions.PopulateGwtDevTools.java

Source

/*******************************************************************************
 * Copyright 2011 Google Inc. All Rights Reserved.
 *
 * 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
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package com.google.gwt.eclipse.devtoolsgen.actions;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
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.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;

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

/**
 * Computes the Google Plugin for Eclipse's transitive dependencies on GWT.
 */
// Steps for generating gwt-dev-tools.jar
//
// 1. Run this plugin using an Eclipse Application launch configuration.
// 
// In the Eclipse you just launched:
// 2. Import the GWT source projects (gwt-dev, gwt-user) and the gwt-dev-tools
// project.
// 3. Set the GWT_TOOLS classpath variable appropriately.
// 4. Add import statements to Deps.java in gwt-dev-tools for all GWT classes
// directly referenced by the GWT plugin.
// 4a. If the new GWT classes have dependencies on new external JAR files, add
// them to the build path of the gwt-dev-tools project (use GWT_TOOLS variable).
// 5. Click the purple Eclipse button in the toolbar. Watch the Console of the
// development workbench as the plugin searches for dependencies.
// 6. When the job finishes, the gwt-dev-tools project should contain exactly
// the transitive set of compilation units needed by the GWT plugin.
// 
// 7. Create a staging directory for the new gwt-dev-tools JAR.
// 8. Copy the gwt-dev-tools bin directory (except Deps.class) into the staging
// directory.
// 9. Unjar the external GWT jars referenced by gwt-dev-tools project into the
// staging directory (make sure not to overwrite existing files).
// 10. Jar the staging directory: "jar -cf gwt-dev-tools.jar -C <staging-dir> ."
// 11. Copy the new gwt-dev-tool.jar to the GWT plugin's /libs directory, and
// then commit the updated gwt-dev-tools.jar and Deps.java.
// 
public class PopulateGwtDevTools implements IWorkbenchWindowActionDelegate {

    private class CopyDepsToGwtDevTools implements IWorkspaceRunnable {

        public void run(IProgressMonitor monitor) throws CoreException {
            IPackageFragmentRoot srcRoot = gwtDevTools.findPackageFragmentRoot(new Path("/gwt-dev-tools/src/"));

            System.out.print("Copying files to gwt-dev-tools...");
            for (IFile dep : deps) {
                IPackageFragment srcPckg = (IPackageFragment) JavaCore.create(dep.getParent());
                IPackageFragment dstPckg = srcRoot.createPackageFragment(srcPckg.getElementName(), false, null);

                dep.copy(dstPckg.getPath().append(dep.getName()), false, null);
            }

            System.out.println("done");
        }
    }

    private class DependencyCollector extends ASTVisitor {

        private final int callGraphLevel;

        public DependencyCollector(int callGraphLevel) {
            this.callGraphLevel = callGraphLevel;
        }

        @Override
        @SuppressWarnings("unchecked")
        public void endVisit(FieldDeclaration node) {
            if (!((CompilationUnit) node.getRoot()).getJavaElement().getElementName().equals("Deps.java")) {
                return;
            }

            for (VariableDeclarationFragment fragment : (List<VariableDeclarationFragment>) node.fragments()) {
                if (fragment.getName().getIdentifier().equals("RESOURCES")) {
                    ArrayInitializer array = (ArrayInitializer) fragment.getInitializer();
                    for (StringLiteral arrayItem : (List<StringLiteral>) array.expressions()) {
                        try {
                            IFile resource = findResourceInGwtProjects(new Path(arrayItem.getLiteralValue()));
                            if (resource != null) {
                                deps.add(resource);
                                printDependency(resource);
                            }
                        } catch (JavaModelException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }

        @Override
        public void endVisit(SimpleName node) {
            IBinding binding = node.resolveBinding();
            if (binding == null) {
                // Ignore nodes for which there is no binding
                return;
            }

            if (binding.getKind() == IBinding.TYPE) {
                ITypeBinding typeBinding = (ITypeBinding) binding;

                try {
                    if (typeBinding.isFromSource()) {
                        String qualifiedTypeName = typeBinding.getQualifiedName();
                        IType type = findTypeInGwtProjects(qualifiedTypeName);
                        if (type != null) {
                            ICompilationUnit cu = type.getCompilationUnit();
                            IFile javaFile = (IFile) cu.getResource();

                            // Ignore compilation units we've already seen
                            if (deps.contains(javaFile)) {
                                return;
                            }

                            deps.add(javaFile);
                            printDependency(javaFile);

                            // Find dependencies pulled in by this compilation unit
                            findAllDependencies(cu, callGraphLevel + 1);
                        }
                    }
                } catch (JavaModelException e) {
                    e.printStackTrace();
                }
            }
        }

        private void printDependency(IFile file) {
            for (int i = 0; i < callGraphLevel; i++) {
                System.out.print("  ");
            }
            System.out.println(file.getFullPath().toString());
        }
    }

    private static IFile findFileOnClasspath(IJavaProject javaProject, IPath classpathRelativePath)
            throws JavaModelException {
        for (IPackageFragmentRoot pckgFragmentRoot : javaProject.getPackageFragmentRoots()) {
            if (pckgFragmentRoot.isArchive()) {
                continue;
            }
            IPath filepath = pckgFragmentRoot.getPath().append(classpathRelativePath);
            IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(filepath);
            if (res instanceof IFile) {
                return (IFile) res;
            }
        }
        return null;
    }

    private static IJavaProject findJavaProject(String name) {
        return JavaCore.create(ResourcesPlugin.getWorkspace().getRoot().getProject(name));
    }

    private Set<IFile> deps = new HashSet<IFile>();

    private final IJavaProject gwtDev = findJavaProject("gwt-dev");

    private final IJavaProject gwtDevTools = findJavaProject("gwt-dev-tools");

    private final IJavaProject gwtUser = findJavaProject("gwt-user");

    public void dispose() {
    }

    public void init(IWorkbenchWindow window) {
    }

    public void run(IAction action) {
        try {
            if (gwtDev == null) {
                System.err.println("Must import the gwt-dev project");
                return;
            }

            if (gwtUser == null) {
                System.err.println("Must import the gwt-user project");
                return;
            }

            if (gwtDevTools == null) {
                System.err.println("Must import the gwt-dev-tools project");
                return;
            }

            System.out.println("Searching for dependecies in GWT source projects...");

            deps.clear();
            IType searchRoot = gwtDevTools.findType("Deps");

            // Find compilation units and resources we depend on
            findAllDependencies(searchRoot.getCompilationUnit(), 0);
            int totalDepsCount = deps.size();

            // Prune out files already in gwt-dev-tools. This eliminates most of the
            // bulk copy when you've already run this tool at least once.
            Iterator<IFile> iter = deps.iterator();
            while (iter.hasNext()) {
                IFile dep = iter.next();

                IJavaElement srcRoot = JavaCore.create(dep.getParent())
                        .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
                IPath srcPathRelativePath = dep.getFullPath().removeFirstSegments(srcRoot.getPath().segmentCount());
                IFile existingFile = findFileOnClasspath(gwtDevTools, srcPathRelativePath);

                if (existingFile != null) {
                    iter.remove();
                }
            }

            System.out.format("Finished dependency search (%d files found; %d new)\n", totalDepsCount, deps.size());

            if (!deps.isEmpty()) {
                IWorkspaceRunnable op = new CopyDepsToGwtDevTools();
                ISchedulingRule lock = ResourcesPlugin.getWorkspace().getRoot();
                ResourcesPlugin.getWorkspace().run(op, lock, IWorkspace.AVOID_UPDATE, null);
            } else {
                System.out.println("Done");
            }
        } catch (CoreException e) {
            e.printStackTrace();
        }
    }

    public void selectionChanged(IAction action, ISelection selection) {
    }

    private void findAllDependencies(ICompilationUnit cu, int callGraphLevel) {
        ASTParser parser = ASTParser.newParser(AST.JLS3);
        parser.setResolveBindings(true);
        parser.setSource(cu);
        CompilationUnit rootCu = (CompilationUnit) parser.createAST(null);
        rootCu.accept(new DependencyCollector(callGraphLevel));
    }

    private IFile findResourceInGwtProjects(IPath classpathRelativePath) throws JavaModelException {
        IFile res = findFileOnClasspath(gwtDev, classpathRelativePath);
        if (res != null) {
            return res;
        }
        return findFileOnClasspath(gwtUser, classpathRelativePath);
    }

    private IType findTypeInGwtProjects(String qualifiedTypeName) throws JavaModelException {
        IType type = gwtDev.findType(qualifiedTypeName);
        if (type != null) {
            return type;
        }

        return gwtUser.findType(qualifiedTypeName);
    }
}