Java tutorial
/* * Copyright (c) 2012, 2013 Eike Stepper (Berlin, Germany) and others. * 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: * Eike Stepper - initial API and implementation */ package org.eclipse.emf.cdo.releng.apireports; import org.eclipse.buckminster.core.actor.AbstractActor; import org.eclipse.buckminster.core.actor.IActionContext; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jdt.core.IClassFile; 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.pde.api.tools.internal.ApiBaselineManager; import org.eclipse.pde.api.tools.internal.comparator.DeltaXmlVisitor; import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; import org.eclipse.pde.api.tools.internal.provisional.Factory; import org.eclipse.pde.api.tools.internal.provisional.IApiAnnotations; import org.eclipse.pde.api.tools.internal.provisional.IApiDescription; import org.eclipse.pde.api.tools.internal.provisional.VisibilityModifiers; import org.eclipse.pde.api.tools.internal.provisional.comparator.ApiComparator; import org.eclipse.pde.api.tools.internal.provisional.comparator.ApiScope; import org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta; import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline; import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; import org.eclipse.pde.api.tools.internal.provisional.model.IApiScope; import org.eclipse.pde.api.tools.internal.provisional.model.IApiTypeRoot; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author Eike Stepper */ public class ApiReportsActor extends AbstractActor { public ApiReportsActor() { } @Override protected IStatus internalPerform(IActionContext context, IProgressMonitor monitor) throws CoreException { Map<String, ? extends Object> properties = context.getAction().getActorProperties(); String baselineName = (String) properties.get("baseline"); if (baselineName == null || baselineName.length() == 0) { return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Baseline name not specified"); } String exclusionPatterns = (String) properties.get("exclude"); String reportFileName = System.getProperty("api.report", new File("api.xml").getAbsolutePath()); SubMonitor progress = SubMonitor.convert(monitor, 100); progress.subTask("Collecting elements to compare"); try { progress.subTask("Computing deltas..."); File reportFile = new File(reportFileName); try { progress.worked(25); updateMonitor(progress); BufferedWriter writer = null; try { if (reportFile.exists()) { reportFile.delete(); } else { File parent = reportFile.getParentFile(); if (!parent.exists() && !parent.mkdirs()) { return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed to create report directory structure"); } } writer = new BufferedWriter(new FileWriter(reportFile)); List<Object> projects = collectProjects(exclusionPatterns); IApiScope scope = walkStructureSelection(projects, monitor); IApiBaseline baseline = ApiBaselineManager.getManager().getApiBaseline(baselineName); if (baseline == null) { return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Baseline not found: " + baselineName); } IDelta delta = ApiComparator.compare(scope, baseline, VisibilityModifiers.API, false, true, monitor); if (delta != null) { progress.worked(25); updateMonitor(progress); DeltaXmlVisitor visitor = new DeltaXmlVisitor(); delta.accept(visitor); writer.write(visitor.getXML()); writer.flush(); progress.worked(25); } } catch (IOException e) { ApiPlugin.log(e); } catch (CoreException e) { ApiPlugin.log(e); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { // ignore } } } progress.worked(25); return Status.OK_STATUS; } catch (OperationCanceledException e) { // ignore } } finally { monitor.done(); } return Status.CANCEL_STATUS; } private List<Object> collectProjects(String exclusionPatterns) { Pattern[] patterns = new Pattern[0]; if (exclusionPatterns != null) { String[] split = exclusionPatterns.split(","); patterns = new Pattern[split.length]; for (int i = 0; i < split.length; i++) { Pattern pattern = Pattern.compile(split[i]); patterns[i] = pattern; } } List<Object> result = new ArrayList<Object>(); for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) { if (project.isAccessible()) { String name = project.getName(); if (!isExcluded(patterns, name)) { IJavaProject javaProject = JavaCore.create(project); if (javaProject != null) { result.add(javaProject); } } } } return result; } private boolean isExcluded(Pattern[] patterns, String name) { for (Pattern pattern : patterns) { Matcher matcher = pattern.matcher(name); if (matcher.matches()) { return true; } } return false; } public static ApiScope walkStructureSelection(List<Object> projects, IProgressMonitor monitor) { ApiScope scope = new ApiScope(); IApiBaseline workspaceBaseline = ApiBaselineManager.getManager().getWorkspaceBaseline(); if (workspaceBaseline == null) { return scope; } Collections.sort(projects, new Comparator() { public int compare(Object o1, Object o2) { if (o1 instanceof IJavaElement && o2 instanceof IJavaElement) { IJavaElement element = (IJavaElement) o1; IJavaElement element2 = (IJavaElement) o2; return element.getElementType() - element2.getElementType(); } return 0; } }); for (Object project : projects) { if (project instanceof IJavaElement) { IJavaElement element = (IJavaElement) project; IJavaProject javaProject = element.getJavaProject(); try { switch (element.getElementType()) { case IJavaElement.COMPILATION_UNIT: { ICompilationUnit compilationUnit = (ICompilationUnit) element; IApiComponent apiComponent = workspaceBaseline .getApiComponent(javaProject.getElementName()); if (apiComponent != null) { addElementFor(compilationUnit, apiComponent, scope); } break; } case IJavaElement.PACKAGE_FRAGMENT: { IPackageFragment fragment = (IPackageFragment) element; IApiComponent apiComponent = workspaceBaseline .getApiComponent(javaProject.getElementName()); IPackageFragmentRoot packageFragmentRoot = (IPackageFragmentRoot) fragment .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); boolean isArchive = false; if (packageFragmentRoot != null) { isArchive = packageFragmentRoot.isArchive(); } if (apiComponent != null) { addElementFor(fragment, isArchive, apiComponent, scope); } break; } case IJavaElement.PACKAGE_FRAGMENT_ROOT: { IPackageFragmentRoot fragmentRoot = (IPackageFragmentRoot) element; IApiComponent apiComponent = workspaceBaseline .getApiComponent(javaProject.getElementName()); if (apiComponent != null) { addElementFor(fragmentRoot, apiComponent, scope); } break; } case IJavaElement.JAVA_PROJECT: IApiComponent apiComponent = workspaceBaseline .getApiComponent(javaProject.getElementName()); if (apiComponent != null) { scope.addElement(apiComponent); } break; } } catch (JavaModelException e) { ApiPlugin.log(e); } catch (CoreException e) { ApiPlugin.log(e); } } } return scope; } private static void addElementFor(IPackageFragmentRoot fragmentRoot, IApiComponent apiComponent, ApiScope scope) throws JavaModelException, CoreException { boolean isArchive = fragmentRoot.isArchive(); IJavaElement[] packageFragments = fragmentRoot.getChildren(); for (int j = 0, max2 = packageFragments.length; j < max2; j++) { IPackageFragment packageFragment = (IPackageFragment) packageFragments[j]; addElementFor(packageFragment, isArchive, apiComponent, scope); } } private static void addElementFor(IPackageFragment packageFragment, boolean isArchive, IApiComponent apiComponent, ApiScope scope) throws JavaModelException, CoreException { // add package fragment elements only if this is an API package IApiDescription apiDescription = apiComponent.getApiDescription(); IApiAnnotations annotations = apiDescription .resolveAnnotations(Factory.packageDescriptor(packageFragment.getElementName())); if (annotations == null || !VisibilityModifiers.isAPI(annotations.getVisibility())) { return; } if (isArchive) { IClassFile[] classFiles = packageFragment.getClassFiles(); for (int i = 0, max = classFiles.length; i < max; i++) { addElementFor(classFiles[i], apiComponent, scope); } } else { ICompilationUnit[] units = packageFragment.getCompilationUnits(); for (int i = 0, max = units.length; i < max; i++) { addElementFor(units[i], apiComponent, scope); } } } private static void addElementFor(IClassFile classFile, IApiComponent apiComponent, ApiScope scope) { try { IApiTypeRoot typeRoot = apiComponent.findTypeRoot(classFile.getType().getFullyQualifiedName()); if (typeRoot != null) { scope.addElement(typeRoot); } } catch (CoreException e) { ApiPlugin.log(e); } } private static void addElementFor(ICompilationUnit compilationUnit, IApiComponent component, ApiScope scope) throws JavaModelException { IType[] types = compilationUnit.getTypes(); for (int i = 0, max = types.length; i < max; i++) { try { IApiTypeRoot typeRoot = component.findTypeRoot(types[i].getFullyQualifiedName()); if (typeRoot != null) { scope.addElement(typeRoot); } } catch (CoreException e) { ApiPlugin.log(e); } } } private static void updateMonitor(IProgressMonitor monitor, int work) throws OperationCanceledException { if (monitor == null) { return; } if (monitor.isCanceled()) { throw new OperationCanceledException(); } monitor.worked(work); } private static void updateMonitor(IProgressMonitor monitor) throws OperationCanceledException { updateMonitor(monitor, 0); } }