Java tutorial
/******************************************************************************* * Copyright (c) 2009 - 2012 SpringSource, a divison of VMware, 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: * SpringSource, a division of VMware, Inc. - initial API and implementation * GianMaria Romanato - add utilities for management of nested plans *******************************************************************************/ package org.eclipse.virgo.ide.facet.core; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; 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.IResourceVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.common.util.WrappedException; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.xmi.PackageNotFoundException; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.ui.statushandlers.StatusManager; import org.eclipse.virgo.ide.facet.internal.core.Plan; import org.eclipse.virgo.ide.facet.internal.core.PlanReader; import org.eclipse.virgo.ide.facet.internal.core.PlanReference; import org.eclipse.virgo.ide.par.Bundle; import org.eclipse.virgo.ide.par.Par; import org.eclipse.virgo.ide.par.ParPackage; import org.eclipse.wst.common.project.facet.core.FacetedProjectFramework; /** * Utility to check if the given {@link IResource} belongs to a project that has the par or bundle facet. * * @author Christian Dupuis * @author Leo Dos Santos * @author GianMaria Romanato * @since 1.0.0 */ public class FacetUtils { /** * Checks if a given {@link IResource} has the bundle facet. */ public static boolean isBundleProject(IResource resource) { return hasNature(resource, JavaCore.NATURE_ID) && hasProjectFacet(resource, FacetCorePlugin.BUNDLE_FACET_ID); } /** * Checks if a given {@link IResource} has the par facet. */ public static boolean isParProject(IResource resource) { return hasProjectFacet(resource, FacetCorePlugin.PAR_FACET_ID); } /** * Checks if a given {@link IResource} has the par facet. */ public static boolean isPlanProject(IResource resource) { return hasProjectFacet(resource, FacetCorePlugin.PLAN_FACET_ID); } /** * Checks if a {@link IResource} has a given project facet. */ public static boolean hasProjectFacet(IResource resource, String facetId) { if (resource != null && resource.isAccessible()) { try { return FacetedProjectFramework.hasProjectFacet(resource.getProject(), facetId); } catch (CoreException e) { StatusManager.getManager().handle(new Status(IStatus.ERROR, FacetCorePlugin.PLUGIN_ID, "An error occurred inspecting project facet", e)); } } return false; } /** * Checks if a {@link IResource} has a given project nature. */ public static boolean hasNature(IResource resource, String natureId) { if (resource != null && resource.isAccessible()) { IProject project = resource.getProject(); if (project != null) { try { return project.hasNature(natureId); } catch (CoreException e) { StatusManager.getManager().handle(new Status(IStatus.ERROR, FacetCorePlugin.PLUGIN_ID, "An error occurred inspecting project nature", e)); } } } return false; } /** * Returns all bundle project in the current workspace regardless weather they are open or closed. */ public static IProject[] getBundleProjects() { List<IProject> bundles = new ArrayList<IProject>(); IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (IProject candidate : projects) { if (FacetUtils.isBundleProject(candidate)) { bundles.add(candidate); } } return bundles.toArray(new IProject[bundles.size()]); } public static IProject[] getParProjects(IProject project) { Set<IProject> bundles = new HashSet<IProject>(); IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (IProject candidate : projects) { if (FacetUtils.isParProject(candidate)) { if (Arrays.asList(getBundleProjects(candidate)).contains(project)) { bundles.add(candidate); } } } return bundles.toArray(new IProject[bundles.size()]); } public static IProject[] getBundleProjects(IProject parProject) { Set<IProject> bundles = new HashSet<IProject>(); if (isParProject(parProject)) { Par par = getParDefinition(parProject); if (par != null && par.getBundle() != null) { for (Bundle bundle : par.getBundle()) { IProject bundleProject = ResourcesPlugin.getWorkspace().getRoot() .getProject(bundle.getSymbolicName()); if (FacetUtils.isBundleProject(bundleProject)) { bundles.add(bundleProject); } } } } return bundles.toArray(new IProject[bundles.size()]); } public static Par getParDefinition(IProject project) { // Create a resource set to hold the resources. ResourceSet resourceSet = new ResourceSetImpl(); // Register the package to ensure it is available during loading. resourceSet.getPackageRegistry().put(ParPackage.eNS_URI, ParPackage.eINSTANCE); File parFile = new File(new File(project.getLocation().toString() + File.separatorChar + ".settings"), "org.eclipse.virgo.ide.runtime.core.par.xml"); if (parFile.exists()) { URI fileUri = URI.createFileURI(parFile.toString()); Resource resource = null; try { resource = resourceSet.getResource(fileUri, true); } catch (WrappedException e) { if (e.getCause() instanceof PackageNotFoundException) { // Handle case where we need to update old par file format. try { BufferedReader br = new BufferedReader(new FileReader(parFile)); StringBuilder sb = new StringBuilder(); String next = br.readLine(); do { next = next.replaceAll("http:///com/springsource/server/ide/par.ecore", "http://eclipse.org/virgo/par.ecore"); next = next.replaceAll("com\\.springsource\\.server", "org.eclipse.virgo"); sb.append(next + "\n"); next = br.readLine(); } while (next != null); br.close(); BufferedWriter bw = new BufferedWriter(new FileWriter(parFile)); bw.write(sb.toString()); bw.close(); project.refreshLocal(IResource.DEPTH_INFINITE, null); resource = resourceSet.getResource(fileUri, true); } catch (IOException e1) { throw new RuntimeException(e1); } catch (CoreException e2) { throw new RuntimeException(e2); } } } return (Par) resource.getContents().iterator().next(); } return null; } public static IFile getParFile(IProject project) { IResource resource = project .findMember(new Path(".settings").append("org.eclipse.virgo.ide.runtime.core.par.xml")); if (resource instanceof IFile) { return (IFile) resource; } return null; } /** * Gets all the plan files found in the given project. * * @param project * @return */ public static Collection<IFile> getPlansInPlanProject(IProject project) { if (!isPlanProject(project)) { return Collections.emptyList(); } final List<IFile> planFiles = new ArrayList<IFile>(); // Collect output locations if java project final Set<IPath> outputLocations = new HashSet<IPath>(); try { if (FacetUtils.hasNature(project, JavaCore.NATURE_ID)) { IJavaProject je = JavaCore.create(project); try { outputLocations.add(je.getOutputLocation()); for (IClasspathEntry entry : je.getRawClasspath()) { if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { if (entry.getOutputLocation() != null) { outputLocations.add(entry.getOutputLocation()); } } } } catch (JavaModelException e) { // safe to ignore } } project.accept(new IResourceVisitor() { public boolean visit(IResource resource) throws CoreException { if (resource.isTeamPrivateMember() || resource.isDerived()) { return false; } if (resource instanceof IFile && "plan".equals(resource.getFileExtension())) { planFiles.add((IFile) resource); } else if (resource instanceof IContainer) { IPath path = ((IContainer) resource).getFullPath(); for (IPath outputLocation : outputLocations) { if (outputLocation.isPrefixOf(path)) { return false; } } return true; } return true; } }); } catch (CoreException e) { // TODO CD log exception } return planFiles; } /** * Returns all the plans in the workspace as a map project to list of plan files * * @return */ private static Map<IProject, Collection<IFile>> getPlansInWorkspace() { Map<IProject, Collection<IFile>> plans = new HashMap<IProject, Collection<IFile>>(); IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (IProject iProject : projects) { if (iProject.isOpen() && isPlanProject(iProject)) { Collection<IFile> ps = getPlansInPlanProject(iProject); plans.put(iProject, ps); } } return plans; } /** * Returns the list of nested plans for a given plan file, including the given plan file as the first one. The look * only in the planFile project, unless the project is also a Java project. In such case, the project classpath is * used to look for plans in required projects. * * @param planFile the plan file * @param recurse whether the method should return only direct children of the file (false) or recurse and collect * all descendants (true) * @return */ public static List<IFile> getNestedPlanFiles(IFile planFile, boolean recurse) { if (!isPlanProject(planFile)) { return Collections.emptyList(); } // parse the top level plan file PlanReader reader = new PlanReader(); Plan topLevelPlan; try { topLevelPlan = reader.read(planFile); } catch (Exception e1) { return Collections.emptyList(); } List<PlanReference> nestedReferences = topLevelPlan.getNestedPlans(); if (nestedReferences.isEmpty()) { return Collections.emptyList(); } List<IFile> nestedPlanFiles = new ArrayList<IFile>(); /* * examine the containing Java project class path (if a Java projecT) and find all the required Java projects. * Nested plans will be searched not only in the current project but also in its dependencies */ List<IProject> orderedProjects = getOrderedProjectDependencies(planFile.getProject()); orderedProjects.add(0, planFile.getProject()); Map<IProject, Collection<IFile>> allPlans = FacetUtils.getPlansInWorkspace(); // used for searching a nested plan that is referred only by name (no version) Map<String, Plan> name2PlanLookup = new HashMap<String, Plan>(); // used for searching a nested plan that is referred by name and version Map<PlanReference, Plan> ref2Plan = new HashMap<PlanReference, Plan>(); // plan to related file Map<PlanReference, IFile> ref2File = new HashMap<PlanReference, IFile>(); // loop over the list of ordered projects and search for plans for (IProject iProject : orderedProjects) { Collection<IFile> candidates = allPlans.get(iProject); if (candidates != null) { for (IFile iFile : candidates) { // ignore self if (!planFile.equals(iFile)) { try { Plan p = reader.read(iFile); PlanReference r = p.asRefence(); /* * in case of duplicate plans (same name and version) first found in classpath wins and * found is assumed to be the right one */ if (!ref2Plan.containsKey(r)) { // add for name+version lookup ref2Plan.put(r, p); /* * in case of duplicates plans with the same name and different version if an outer plan * is referring to a nested plan via name only, the first found in classpath wins */ if (!name2PlanLookup.containsKey(r.getName())) { name2PlanLookup.put(r.getName(), p); } ref2File.put(r, iFile); } } catch (Exception e) { // ignore } } } } } // finally compute the list of nested plans. Use a queue instead of recursion. Queue<PlanReference> toBeProcessed = new ArrayBlockingQueue<PlanReference>(ref2Plan.size() + 1); Set<PlanReference> alreadyProcessed = new HashSet<PlanReference>(); toBeProcessed.addAll(nestedReferences); while (toBeProcessed.peek() != null) { PlanReference planReference = toBeProcessed.poll(); alreadyProcessed.add(planReference); // search for exact match name + version Plan nestedPlan = ref2Plan.get(planReference); // search for exact match name + version if (nestedPlan == null && planReference.getVersion() == null) { nestedPlan = name2PlanLookup.get(planReference.getName()); } if (nestedPlan != null) { IFile nestedFile = ref2File.get(nestedPlan.asRefence()); nestedPlanFiles.add(nestedFile); for (PlanReference aRef : nestedPlan.getNestedPlans()) { if (recurse && !alreadyProcessed.contains(aRef)) { toBeProcessed.add(aRef); } } } } return nestedPlanFiles; } /** * Returns the ordered list of project dependencies for the given Java project or an empty list if the project is * not a Java project. * * @param project the Java project * @return the list of required projects */ private static List<IProject> getOrderedProjectDependencies(IProject project) { LinkedHashSet<IProject> projects = new LinkedHashSet<IProject>(); if (FacetUtils.hasNature(project, JavaCore.NATURE_ID)) { IJavaProject je = JavaCore.create(project); String[] names; try { names = je.getRequiredProjectNames(); for (String prjName : names) { IProject prj = ResourcesPlugin.getWorkspace().getRoot().getProject(prjName); if (prj.exists() && prj.isOpen() && isPlanProject(prj)) { projects.add(prj); projects.addAll(getOrderedProjectDependencies(prj)); } } } catch (JavaModelException e) { } } return new ArrayList<IProject>(projects); } }