Package org.maven.ide.eclipse.scala

Source Code of org.maven.ide.eclipse.scala.ScalaProjectConfigurator

/*******************************************************************************
* Copyright (c) 2008 Sonatype, 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
*******************************************************************************/

package org.maven.ide.eclipse.scala;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.MojoExecution;
import org.eclipse.core.resources.IProject;
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.jdt.core.ClasspathContainerInitializer;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathContainer;
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.jdt.internal.core.ClasspathAttribute;
import org.eclipse.m2e.core.project.IMavenProjectFacade;
import org.eclipse.m2e.core.project.configurator.ProjectConfigurationRequest;
import org.eclipse.m2e.jdt.AbstractJavaProjectConfigurator;
import org.eclipse.m2e.jdt.IClasspathDescriptor;
import org.eclipse.m2e.jdt.IClasspathEntryDescriptor;

//TODO check the jre/java version compliance (>= 1.5)
//TODO check JDT Weaving is enabled (if not enabled, icon of scala file is [J] same as java (and property of  the file display "Type :... Java Source File" )
//TODO check that pom.xml and ScalaLib Container declare the same scala version
//TODO keep sync scala-compiler configuration between pom.xml and scala-plugin ? (sync bi-direction) ?
//TODO ask sonatype/mailing-list about how to retreive maven plugin configuration, like additional sourceDirectory
/**
* @author Sonatype Inc (http://github.com/sonatype/m2eclipse-scala)
* @author davidB (http://github.com/davidB)
* @author germanklf  (http://github.com/germanklf)
* @author Fred Bricon
*/
public class ScalaProjectConfigurator extends AbstractJavaProjectConfigurator {


  private static final String SCALA_CONTAINER_PATH = "org.scala-ide.sdt.launching.SCALA_CONTAINER";

  private static final String MAVEN_CONTAINER_PATH = "org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER";

  private static String DEPLOYABLE_KEY = "org.eclipse.jst.component.dependency";

  private static String NON_DEPLOYABLE_KEY = "org.eclipse.jst.component.nondependency";

  private Map<String, Integer> mapSourceTypeWeight;

  private Map<String, Integer> mapResourceWeight;

  private Comparator<IClasspathEntry> comparator;

  public ScalaProjectConfigurator() {
    super();

    mapSourceTypeWeight = new HashMap<String, Integer>();
    mapSourceTypeWeight.put("src/main/", 9000);
    mapSourceTypeWeight.put("src/test/", 1000);

    mapResourceWeight = new HashMap<String, Integer>();
    mapResourceWeight.put("java", 100);
    mapResourceWeight.put("resources", -10);

    comparator = new Comparator<IClasspathEntry>() {
      public int compare(IClasspathEntry o1, IClasspathEntry o2) {
        Integer w1 = getWeight(o1);
        Integer w2 = getWeight(o2);
        if(w1 > 0 || w2 > 0) {
          if(w1.equals(w2))
            return o1.getPath().toString().compareTo(o2.getPath().toString());
          else
            return w1.compareTo(w2) * -1;
        }
        return 0;
      }

      private Integer getWeight(IClasspathEntry ce) {
        int value = 0;
        if(ce.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
          for(Entry<String, Integer> e : mapSourceTypeWeight.entrySet()) {
            if(ce.getPath().toString().contains(e.getKey())) {
              value += e.getValue();
            }
          }
          for(Entry<String, Integer> e : mapResourceWeight.entrySet()) {
            if(ce.getPath().toString().endsWith(e.getKey())) {
              value += e.getValue();
            }
          }
        }
        return value;
      }
    };
  }

  private String scalaNatureId() {
    ScalaPluginIds ids = Activator.getInstance().scalaPluginIds();
    return (ids == null)?null : ids.natureId;
  }
 
//  private boolean shouldManageClasspath() {
//    Version v4 = new Version(4,0,0);
//    return v4.compareTo(Activator.getInstance().scalaPluginIds().version) > 0;
//  }

  @Override
  public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException {
    super.configure(request, monitor);
    String scalaNature = scalaNatureId();
    if (scalaNature == null) {
      //TODO show an alert to user that he should to install scala-ide plugin;
      return;
    }
    try {
      if (request != null)  {
        IProject project = request.getProject();
        if(!project.hasNature(scalaNature) && isScalaProject(request.getMavenProjectFacade(), monitor)) {
          if(!project.hasNature("org.eclipse.jdt.core.javanature")) {
            addNature(project, "org.eclipse.jdt.core.javanature", monitor);
          }
          addNature(project, scalaNature, monitor);
        }
      }
    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * configure Classpath : contain of "Maven Dependencies" Librairies Container.
   */
  @Override
  public void configureClasspath(IMavenProjectFacade facade, IClasspathDescriptor classpath, IProgressMonitor monitor) throws CoreException {
    String scalaNature = scalaNatureId();
    if (scalaNature == null) {
      //TODO show an alert to user that he should to install scala-ide plugin;
      return;
    }
    if (!isLaunchConfigurationCtx()) {
      IProject project = facade.getProject();
      if(isScalaProject(project)) {
  //      if(!project.hasNature(ID_NATURE)) {
  //        addNature(project, ID_NATURE, monitor);
  //      }
        removeScalaFromMavenContainer(classpath);
        sortContainerScalaJre(project, monitor); //
        makeScalaLibDeployable(facade, classpath, monitor);
      }
    }
  }

  // workaround to avoid NPE
  @Override
  protected IPath getFullPath( IMavenProjectFacade facade, File file ) {
    if (file == null) return null;
    return super.getFullPath(facade, file);
  }

  private void removeScalaFromMavenContainer(final IClasspathDescriptor classpath) {
    classpath.removeEntry(new IClasspathDescriptor.EntryFilter() {
      public boolean accept(IClasspathEntryDescriptor descriptor) {
        boolean back = "org.scala-lang".equals(descriptor.getGroupId());
        //TODO, use content of Scala Library Container instead of hardcoded value
        back = back && ("scala-library".equals(descriptor.getArtifactId())
        //|| "scala-compiler".equals(descriptor.getArtifactId())
            || "scala-dbc".equals(descriptor.getArtifactId()) || "scala-swing".equals(descriptor.getArtifactId()));
        return back;
      }
    });
  }

  /**
   * Check and reorder Containers : "Scala Lib" should be before "JRE Sys",
   * else 'Run Scala Application' set Boot Entries JRE before Scala and failed with scala.* NotFound Exception.
   * Should already be done when adding nature
   * @see scala.tools.eclipse.Nature#configure()
   */
  private void sortContainerScalaJre(final IProject project, IProgressMonitor monitor) throws CoreException {
    IJavaProject javaProject = JavaCore.create(project);
    IClasspathEntry[] classpathEntries = javaProject.getRawClasspath();

    Boolean sorted = true;
    for (int i = 0; i < classpathEntries.length - 1; i++) {
      if (comparator.compare(classpathEntries[i], classpathEntries[i+1]) > 0){sorted = false; break;}
    }

    if(!sorted) {
      List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(classpathEntries.length);
      Collections.addAll(entries, classpathEntries);

      Collections.sort(entries, comparator);
      javaProject.setRawClasspath(entries.toArray(new IClasspathEntry[entries.size()]), monitor);
    }
  }

  private boolean isScalaProject(IProject project) {
    try {
      return project != null && project.isAccessible() && project.hasNature(scalaNatureId());
    } catch(CoreException e) {
      return false;
    }
  }

  private boolean isScalaProject(IMavenProjectFacade facade, IProgressMonitor monitor) throws CoreException {
    List<Plugin> plugins = facade.getMavenProject(monitor).getBuildPlugins();
    if(plugins != null) {
      for(Plugin plugin : plugins) {
        if(isMavenBundlePluginMojo(plugin) && !plugin.getExecutions().isEmpty()) {
          return true;
        }
      }
    }
    return false;
  }

  protected boolean isLaunchConfigurationCtx() {
    for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
      if ("launch".equals(e.getMethodName())) {
        return true;
      }
    }
    return false;
  }

  protected boolean isMavenBundlePluginMojo(MojoExecution execution) {
    return isMavenBundlePluginMojo(execution.getGroupId(), execution.getArtifactId());
  }

  private boolean isMavenBundlePluginMojo(Plugin plugin) {
    return isMavenBundlePluginMojo(plugin.getGroupId(), plugin.getArtifactId());
  }

  private boolean isMavenBundlePluginMojo(String groupId, String artifactId) {
    return ("org.scala-tools".equals(groupId) && "maven-scala-plugin".equals(artifactId))
     || ("net.alchim31.maven".equals(groupId) && "scala-maven-plugin".equals(artifactId));
  }

  @SuppressWarnings("restriction")
  private void makeScalaLibDeployable(IMavenProjectFacade facade, IClasspathDescriptor classpath, IProgressMonitor monitor) throws CoreException {

    IJavaProject javaProject = JavaCore.create(facade.getProject());
    if (javaProject == null) {
      return;
    }

    IClasspathEntry scalaLibrary = getContainer(javaProject, SCALA_CONTAINER_PATH);

    if (scalaLibrary == null) {
      //Really nothing to do here
      return;
    }

    IClasspathEntry mavenLibrary = getContainer(javaProject, MAVEN_CONTAINER_PATH);

    IClasspathAttribute deployableAttribute = getDeployableAttribute(mavenLibrary);
    //If the Maven Classpath Container is set to be deployed in WTP, then do the same for the Scala one
    if (deployableAttribute != null) {
      //Add the deployable attribute only if it's not set already.
      if (getDeployableAttribute(scalaLibrary) == null) {
        addDeployableAttribute(javaProject, deployableAttribute, monitor);
      }
    }

  }

  private static void addDeployableAttribute(IJavaProject javaProject, IClasspathAttribute deployableAttribute, IProgressMonitor monitor) throws JavaModelException, CoreException {
    if (javaProject == null) return;
    ClasspathContainerInitializer scalaInitializer = JavaCore.getClasspathContainerInitializer(SCALA_CONTAINER_PATH);
    if (scalaInitializer == null) return;
    IPath scalaContainerPath = Path.fromPortableString(SCALA_CONTAINER_PATH);
    Boolean updateAble = scalaInitializer.canUpdateClasspathContainer(scalaContainerPath, javaProject);
    final IClasspathContainer scalaLibrary = JavaCore.getClasspathContainer(scalaContainerPath, javaProject);
    final IClasspathEntry[] cpEntries = scalaLibrary.getClasspathEntries();

    for(int i = 0; i < cpEntries.length; i++ ) {
      IClasspathEntry cpe = cpEntries[i];
      LinkedHashMap<String, IClasspathAttribute> attrs = new LinkedHashMap<String, IClasspathAttribute>();
      for(IClasspathAttribute attr : cpe.getExtraAttributes()) {
        //Keep all existing attributes except the non_deployable key
        if(!attr.getName().equals(NON_DEPLOYABLE_KEY)) {
          attrs.put(attr.getName(), attr);
        }
      }
      attrs.put(deployableAttribute.getName(), deployableAttribute);
      IClasspathAttribute[] newAttrs = attrs.values().toArray(new IClasspathAttribute[attrs.size()]);
      cpEntries[i] = JavaCore.newLibraryEntry(cpe.getPath(), cpe.getSourceAttachmentPath(),
          cpe.getSourceAttachmentRootPath(), cpe.getAccessRules(), newAttrs, cpe.isExported());
    }

    IClasspathContainer candidateScalaContainer = new IClasspathContainer() {
      public IPath getPath() { return scalaLibrary.getPath(); }
      public IClasspathEntry[] getClasspathEntries() { return cpEntries; }
      public String getDescription() { return scalaLibrary.getDescription(); }
      public int getKind() { return scalaLibrary.getKind(); }
    };

    if (updateAble){
      scalaInitializer.requestClasspathContainerUpdate(scalaContainerPath, javaProject, candidateScalaContainer);
    } else {
      IJavaProject [] jPArray = { javaProject };
      IClasspathContainer[] cpArray = { candidateScalaContainer };
      JavaCore.setClasspathContainer(scalaContainerPath, jPArray, cpArray, null);
    }
  }

  private static IClasspathEntry getContainer(IJavaProject javaProject, String containerPath) throws JavaModelException {
    IClasspathEntry[] cp = javaProject.getRawClasspath();
    for(int i = 0; i < cp.length; i++ ) {
      if(IClasspathEntry.CPE_CONTAINER == cp[i].getEntryKind()
          && containerPath.equals(cp[i].getPath().lastSegment())) {
        return cp[i];
      }
    }
    return null;
  }

  private static IClasspathAttribute getDeployableAttribute(IClasspathEntry library) {
    if (library == null) {
      return null;
    }

    IClasspathAttribute[] attributes = library.getExtraAttributes();
    if (attributes == null || attributes.length == 0) {
      return null;
    }

    for(IClasspathAttribute attr : attributes) {
      if (DEPLOYABLE_KEY.equals(attr.getName())) {
           return new ClasspathAttribute(attr.getName(), attr.getValue());
      }
    }
    return null;
  }
}
TOP

Related Classes of org.maven.ide.eclipse.scala.ScalaProjectConfigurator

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.