/******************************************************************************* * 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_tool; import java.io.ByteArrayInputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IPackageDeclaration; 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.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.handlers.HandlerUtil; import org.eclipse.ui.ide.IDE; /** * Traverse the known world, building a list of WindowTester types and members for * inclusion in WTConvertAPIContextBuilder. This information is written to the files * "wt-types-yyyymmddhhmmss.txt" and "wt-static-members-yyyymmddhhmmss.txt" in the * com.windowtester.eclipse.ui/src/com/windowtester/eclipse/ui/convert folder. This file * should be merged into the wt-types.txt and wt-static-members.txt files respectively * residing in the same directory. */ public class WTConvertAPIContextBuilderTool extends AbstractHandler { private Shell wbShell; private Set<String> wtTypes; private Set<String> wtStaticMembers; /** * Scan the workspace and create the files. */ public Object execute(ExecutionEvent event) throws ExecutionException { wbShell = HandlerUtil.getActiveWorkbenchWindow(event).getShell(); // Instantiate the files to be written String ymdhms = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); IFile wtTypesFile = getFile("wt-types", ymdhms); if (wtTypesFile == null) return null; IFile wtStaticMembersFile = getFile("wt-static-members", ymdhms); if (wtStaticMembersFile == null) return null; // Scan the workspace for WindowTester types and members try { new ProgressMonitorDialog(wbShell).run(true, true, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { scanWorkspace(monitor); } catch (Exception e) { throw new InvocationTargetException(e); } } }); } catch (Exception e) { if (e instanceof InvocationTargetException) e = (InvocationTargetException) e; new ExceptionDetailsDialog(wbShell, "Exception", "Failed to generate content for " + wtTypesFile.getFullPath(), e).open(); return null; } // Write the results to the files writeFile(wtTypesFile, wtTypes); writeFile(wtStaticMembersFile, wtStaticMembers); // Open the files in an editor try { IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); IDE.openEditor(activePage, wtTypesFile); IDE.openEditor(activePage, wtStaticMembersFile); } catch (PartInitException e) { new ExceptionDetailsDialog(wbShell, "Exception", "Failed to open editors for generated files.", e); } return null; } /** * Answer the file in the * com.windowtester.eclipse.ui/src/com/windowtester/eclipse/ui/convert folder * * @param filePrefix the file prefix (e.g. "wt-types") * @param ymdhms the file suffix (e.g. the year, month, day, ...) * @return the file or <code>null</code> if there was a problem getting the file not * exist) */ private IFile getFile(String filePrefix, String ymdhms) { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("com.windowtester.eclipse.ui"); if (!project.exists()) { MessageDialog.openError(wbShell, "Missing Project", "Failed to find project " + project.getName()); return null; } IFolder folder = project.getFolder(new Path("src/com/windowtester/eclipse/ui/convert")); if (!folder.exists()) { MessageDialog.openError(wbShell, "Missing Folder", "Failed to folder " + folder.getFullPath()); return null; } return folder.getFile(filePrefix + "-" + ymdhms + ".txt"); } /** * Write the element to the specified file * * @param file the file (not <code>null</code>) * @param elements the elements (not <code>null</code> and contains no * <code>null</code> s) */ private void writeFile(IFile file, Set<String> elements) { StringWriter stringWriter = new StringWriter(1000); PrintWriter writer = new PrintWriter(stringWriter); for (Iterator<String> iter = new TreeSet<String>(elements).iterator(); iter.hasNext();) writer.println(iter.next()); writer.flush(); try { file.create(new ByteArrayInputStream(stringWriter.toString().getBytes()), false, null); } catch (CoreException e) { new ExceptionDetailsDialog(wbShell, "Exception", "Failed to create file " + file.getFullPath(), e); } } /** * Recursively iterate over all projects in the workspace looking for WindowTester * classes and members. * * @param monitor the progress monitor (not <code>null</code>) */ private void scanWorkspace(IProgressMonitor monitor) throws CoreException { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); wtTypes = new HashSet<String>(); wtStaticMembers = new HashSet<String>(); IProject[] allProjects = root.getProjects(); monitor.beginTask("Scanning Projects", allProjects.length + 1); for (int i = 0; i < allProjects.length; i++) { monitor.worked(1); IProject project = allProjects[i]; scanProject(project); } monitor.done(); } /** * Recursively iterate over all elements in the project looking for WindowTester * classes and members. * * @param proj the java project (not <code>null</code>) */ private void scanProject(IProject proj) throws JavaModelException { if (!proj.exists()) return; String projName = proj.getName(); if (!projName.startsWith("com.windowtester.") || projName.indexOf('_') != -1) return; if (projName.endsWith(".recorder") || projName.endsWith(".help") || projName.endsWith(".codegen")) return; if (projName.equals("com.windowtester.eclipse.ui")) return; IJavaProject javaProject = JavaCore.create(proj); if (!javaProject.exists()) return; IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots(); for (int i = 0; i < roots.length; i++) scanPackageRoot(roots[i]); } /** * Recursively iterate over the elements in the specified java element looking for * WindowTester classes and members. * * @param root the package fragment root (not <code>null</code>) */ private void scanPackageRoot(IPackageFragmentRoot root) throws JavaModelException { if (root.getKind() != IPackageFragmentRoot.K_SOURCE) return; IJavaElement[] children = root.getChildren(); for (int i = 0; i < children.length; i++) scanElement(children[i]); } /** * Recursively iterate over the specified java element and their children looking for * WindowTester classes and members. * * @param elem the java element (not <code>null</code>) */ private void scanElement(IJavaElement elem) throws JavaModelException { switch (elem.getElementType()) { case IJavaElement.PACKAGE_FRAGMENT : scanPackage((IPackageFragment) elem); break; case IJavaElement.COMPILATION_UNIT : scanCompilationUnit((ICompilationUnit) elem); break; default : break; } } /** * Recursively iterate over the elements in the specified java element looking for * WindowTester classes and members. * * @param pkg the package fragment (not <code>null</code>) */ private void scanPackage(IPackageFragment pkg) throws JavaModelException { System.out.println(pkg.getElementName()); IJavaElement[] children = pkg.getChildren(); for (int i = 0; i < children.length; i++) scanElement(children[i]); } /** * Scan the specified compilation unit looking for WindowTester classes and members. * * @param compUnit the compilation unit (not <code>null</code>) */ private void scanCompilationUnit(ICompilationUnit compUnit) throws JavaModelException { IPackageDeclaration[] allPackageDeclarations = compUnit.getPackageDeclarations(); if (allPackageDeclarations == null || allPackageDeclarations.length == 0) return; String packageName = allPackageDeclarations[0].getElementName(); IType[] allTypes = compUnit.getTypes(); for (int i = 0; i < allTypes.length; i++) scanType(packageName, allTypes[i]); } /** * Scan the specified top level type looking for WindowTester classes and members. * * @param packageName the name of the package containing the type (not * <code>null</code>, not empty) * @param type the type (not <code>null</code>) */ private void scanType(String packageName, IType type) throws JavaModelException { if (!Flags.isPublic(type.getFlags())) return; boolean isInterface = type.isInterface(); String fullyQualifiedClassName = packageName + "." + type.getElementName(); wtTypes.add(fullyQualifiedClassName); IField[] allFields = type.getFields(); for (int i = 0; i < allFields.length; i++) { IField field = allFields[i]; if (isInterface || (Flags.isPublic(field.getFlags()) && Flags.isStatic(field.getFlags()))) wtStaticMembers.add(fullyQualifiedClassName + "." + field.getElementName()); } IMethod[] allMethods = type.getMethods(); for (int i = 0; i < allMethods.length; i++) { IMethod method = allMethods[i]; if (isInterface || (Flags.isPublic(method.getFlags()) && Flags.isStatic(method.getFlags()))) wtStaticMembers.add(fullyQualifiedClassName + "." + method.getElementName() + "()"); } IType[] allTypes = type.getTypes(); for (int i = 0; i < allTypes.length; i++) { IType memberType = allTypes[i]; if (isInterface || (Flags.isPublic(memberType.getFlags()) && Flags.isStatic(memberType.getFlags()))) scanType(fullyQualifiedClassName, memberType); } } }