Package org.cloudfoundry.ide.eclipse.server.standalone.internal.application

Source Code of org.cloudfoundry.ide.eclipse.server.standalone.internal.application.JavaPackageFragmentRootHandler

/*******************************************************************************
* Copyright (c) 2013, 2014 Pivotal Software, Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Apache License,
* Version 2.0 (the "License�); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*  Contributors:
*     Pivotal Software, Inc. - initial API and implementation
********************************************************************************/
package org.cloudfoundry.ide.eclipse.server.standalone.internal.application;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.cloudfoundry.ide.eclipse.server.core.internal.CloudErrorUtil;
import org.cloudfoundry.ide.eclipse.server.core.internal.CloudFoundryPlugin;
import org.cloudfoundry.ide.eclipse.server.standalone.internal.Messages;
import org.cloudfoundry.ide.eclipse.server.standalone.internal.startcommand.JavaTypeResolver;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
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.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
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.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
import org.eclipse.jdt.launching.JavaRuntime;

/**
* Resolves all the package fragment roots and main type for a give Java
* project. It includes handling all required Java projects for the given java
* project.
*
*/
public class JavaPackageFragmentRootHandler {

  private IJavaProject javaProject;

  private IType type;

  public JavaPackageFragmentRootHandler(IJavaProject javaProject, IType type) {
    this.type = type;
    this.javaProject = javaProject;
  }

  public IPackageFragmentRoot[] getPackageFragmentRoots(
      IProgressMonitor monitor) throws CoreException {
    IType type = getMainType(monitor);

    ILaunchConfiguration configuration = createConfiguration(type);
    IPath[] classpathEntries = getRuntimeClasspaths(configuration);

    List<IPackageFragmentRoot> pckRoots = new ArrayList<IPackageFragmentRoot>();

    // Since the java project may have other required projects, fetch the
    // ordered
    // list of required projects that will be used to search for package
    // fragment roots
    // corresponding to the resolved class paths. The order of the java
    // projects to search in should
    // start with the most immediate list of required projects of the java
    // project.
    List<IJavaProject> javaProjectsToSearch = getOrderedJavaProjects(javaProject);

    // Find package fragment roots corresponding to the path entries.
    // Search through all java projects, not just the immediate java project
    // for the application that is being pushed to CF.
    for (IPath path : classpathEntries) {

      for (IJavaProject javaProject : javaProjectsToSearch) {

        try {
          IPackageFragmentRoot[] roots = javaProject
              .getPackageFragmentRoots();

          if (roots != null) {
            List<IPackageFragmentRoot> foundRoots = new ArrayList<IPackageFragmentRoot>();

            for (IPackageFragmentRoot packageFragmentRoot : roots) {
              // Note that a class path entry may correspond to a
              // Java project's target directory.
              // Different fragment roots may use the same target
              // directory, so relationship between fragment roots
              // to a class path entry may be many-to-one.

              if (isRootAtEntry(packageFragmentRoot, path)) {
                foundRoots.add(packageFragmentRoot);
              }
            }

            // Stop after the first successful search
            if (!foundRoots.isEmpty()) {
              pckRoots.addAll(foundRoots);
              break;
            }
          }

        } catch (Exception e) {
          throw CloudErrorUtil.toCoreException(e);
        }
      }

    }

    return pckRoots.toArray(new IPackageFragmentRoot[pckRoots.size()]);

  }

  /**
   * Attempts to resolve a main type in the associated Java project. Throws
   * {@link CoreException} if it failed to resolve main type or no main type
   * found.
   *
   * @param monitor
   * @return non-null Main type.
   * @throws CoreException
   *             if failure occurred while resolving main type or no main type
   *             found
   */
  public IType getMainType(IProgressMonitor monitor) throws CoreException {
    if (type == null) {
      type = new JavaTypeResolver(javaProject)
          .getMainTypesFromSource(monitor);
      if (type == null) {
        throw CloudErrorUtil
            .toCoreException(Messages.JavaCloudFoundryArchiver_ERROR_NO_MAIN);
      }
    }
    return type;
  }

  protected List<IJavaProject> getOrderedJavaProjects(IJavaProject project) {
    List<String> collectedProjects = new ArrayList<String>();
    getOrderedJavaProjectNames(
        Arrays.asList(project.getProject().getName()),
        collectedProjects);

    List<IJavaProject> projects = new ArrayList<IJavaProject>();

    for (String name : collectedProjects) {
      IProject prj = ResourcesPlugin.getWorkspace().getRoot()
          .getProject(name);
      if (prj != null) {
        IJavaProject jvPrj = JavaCore.create(prj);
        if (jvPrj != null && jvPrj.exists()) {
          projects.add(jvPrj);
        }
      }
    }

    return projects;

  }

  protected void getOrderedJavaProjectNames(
      List<String> sameLevelRequiredProjects,
      List<String> collectedProjects) {
    // The order in which required projects are collected is as follows,
    // with the RHS
    // being required projects of the LHS
    // A -> BC
    // B -> D
    // C -> E
    // = total 5 projects, added in the order that they are encountered.
    // so final ordered list should be ABCDE
    if (sameLevelRequiredProjects == null) {
      return;
    }
    List<String> nextLevelRequiredProjects = new ArrayList<String>();
    // First add the current level java projects in the order they appear
    // and also collect each one's required names.
    for (String name : sameLevelRequiredProjects) {
      try {
        IProject project = ResourcesPlugin.getWorkspace().getRoot()
            .getProject(name);
        if (project != null) {
          IJavaProject jvPrj = JavaCore.create(project);
          if (jvPrj != null && jvPrj.exists()) {
            if (!collectedProjects.contains(name)) {
              collectedProjects.add(name);
            }
            String[] names = jvPrj.getRequiredProjectNames();
            if (names != null && names.length > 0) {
              for (String reqName : names) {
                if (!nextLevelRequiredProjects
                    .contains(reqName)) {
                  nextLevelRequiredProjects.add(reqName);
                }
              }
            }
          }
        }

      } catch (JavaModelException e) {
        CloudFoundryPlugin.logError(e);
      }

    }

    // Now recurse to fetch the required projects for the
    // list of java projects that were added at the current level above
    if (!nextLevelRequiredProjects.isEmpty()) {
      getOrderedJavaProjectNames(nextLevelRequiredProjects,
          collectedProjects);

    }
  }

  protected ILaunchConfiguration createConfiguration(IType type)
      throws CoreException {

    ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();

    ILaunchConfigurationType configType = manager
        .getLaunchConfigurationType(IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION);

    ILaunchConfigurationWorkingCopy workingCopy = configType.newInstance(
        null, manager.generateLaunchConfigurationName(type
            .getTypeQualifiedName('.')));
    workingCopy.setAttribute(
        IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME,
        type.getFullyQualifiedName());
    workingCopy.setAttribute(
        IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, type
            .getJavaProject().getElementName());
    workingCopy.setMappedResources(new IResource[] { type
        .getUnderlyingResource() });
    return workingCopy.doSave();
  }

  protected IPath[] getRuntimeClasspaths(ILaunchConfiguration configuration)
      throws CoreException {
    IRuntimeClasspathEntry[] entries = JavaRuntime
        .computeUnresolvedRuntimeClasspath(configuration);
    entries = JavaRuntime.resolveRuntimeClasspath(entries, configuration);

    ArrayList<IPath> userEntries = new ArrayList<IPath>(entries.length);
    for (int i = 0; i < entries.length; i++) {
      if (entries[i].getClasspathProperty() == IRuntimeClasspathEntry.USER_CLASSES) {

        String location = entries[i].getLocation();
        if (location != null) {
          IPath entry = Path.fromOSString(location);
          if (!userEntries.contains(entry)) {
            userEntries.add(entry);
          }
        }
      }
    }
    return userEntries.toArray(new IPath[userEntries.size()]);
  }

  /**
   *
   * Determines if the given package fragment root corresponds to the class
   * path entry path.
   * <p/>
   * Note that different package fragment roots may point to the same class
   * path entry.
   * <p/>
   * Example:
   * <p/>
   * A Java project may have the following package fragment roots:
   * <p/>
   * - src/main/java
   * <p/>
   * - src/main/resources
   * <p/>
   * Both may be using the same output folder:
   * <p/>
   * target/classes.
   * <p/>
   * In this case, the output folder will have a class path entry - target/classes - and it will be the same
   * for both roots, and this method will return true for both roots if passed the entry for target/classes
   *
   * @param root
   *            to check if it corresponds to the given class path entry path
   * @param entry
   * @return true if root is at the given entry
   */
  private static boolean isRootAtEntry(IPackageFragmentRoot root, IPath entry) {
    try {
      IClasspathEntry cpe = root.getRawClasspathEntry();
      if (cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
        IPath outputLocation = cpe.getOutputLocation();
        if (outputLocation == null) {
          outputLocation = root.getJavaProject().getOutputLocation();
        }

        IPath location = ResourcesPlugin.getWorkspace().getRoot()
            .findMember(outputLocation).getLocation();
        if (entry.equals(location)) {
          return true;
        }
      }
    } catch (JavaModelException e) {
      CloudFoundryPlugin.logError(e);
    }

    IResource resource = root.getResource();
    if (resource != null && entry.equals(resource.getLocation())) {
      return true;
    }

    IPath path = root.getPath();
    if (path != null && entry.equals(path)) {
      return true;
    }

    return false;
  }
}
TOP

Related Classes of org.cloudfoundry.ide.eclipse.server.standalone.internal.application.JavaPackageFragmentRootHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.