org.springsource.ide.eclipse.gradle.core.ClassPath.java Source code

Java tutorial

Introduction

Here is the source code for org.springsource.ide.eclipse.gradle.core.ClassPath.java

Source

/*******************************************************************************
 * Copyright (c) 2012 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:
 * VMWare, Inc. - initial API and implementation
 *******************************************************************************/
package org.springsource.ide.eclipse.gradle.core;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.JavaRuntime;

/**
 * Helper class to simplify manipulation of a project's class path.
 * @author Kris De Volder
 */
public class ClassPath {

    public static boolean isContainerOnClasspath(IJavaProject jp, String containerID) {
        try {
            IClasspathEntry[] entries = jp.getRawClasspath();
            for (IClasspathEntry e : entries) {
                if (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
                    IPath path = e.getPath();
                    if (containerID.equals(path.segment(0))) {
                        return true;
                    }
                }
            }
        } catch (JavaModelException e) {
            GradleCore.log(e);
        }
        return false;
    }

    /**
     * This array defines the ordering classpath entries based on their kinds.
     */
    public static final int[] kindOrdering = { IClasspathEntry.CPE_SOURCE, IClasspathEntry.CPE_PROJECT,
            IClasspathEntry.CPE_LIBRARY, IClasspathEntry.CPE_CONTAINER, IClasspathEntry.CPE_VARIABLE };

    private static int MAX_ORDER_CAT = 5; //Will be used for anything that falls outside the kindOrderCat classification (but shouldn't be any). 

    /**
     * Entries, divided-up by category so that categories always maintain their order no matter
     * what order entries are added in.
     */
    @SuppressWarnings("unchecked")
    private Map<Integer, Collection<IClasspathEntry>> entryMap = new HashMap<Integer, Collection<IClasspathEntry>>(
            kindOrdering.length);

    public class ClasspathEntryComparator implements Comparator<IClasspathEntry> {
        public int compare(IClasspathEntry e1, IClasspathEntry e2) {
            int k1 = e1.getEntryKind();
            int k2 = e2.getEntryKind();
            Assert.isLegal(k1 == k2, "Only entries with the same kind should be compared");
            String p1 = e1.getPath().toString();
            String p2 = e2.getPath().toString();
            return p1.compareTo(p2);
        }
    }

    private boolean enableSorting; //If true, entries of the same kind will be sorted otherwise they will retained in the order they are being added.

    /** 
     * Create a classpath prepopoluated with a set of raw classpath entries.
     * 
     * @param project 
     * @param i
     */
    public ClassPath(GradleProject project, IClasspathEntry[] rawEntries) {
        this(project);
        addAll(Arrays.asList(rawEntries));
    }

    /**
     * Create an empty classpath. 
     * @param size   Hint about the size the classpath will likely be after all elements have been added.
     */
    public ClassPath(GradleProject project, int size) {
        this(project);
    }

    private ClassPath(GradleProject project) {
        this.enableSorting = project.getProjectPreferences().getEnableClasspatEntrySorting();
    }

    public Collection<IClasspathEntry> createEntrySet(int size) {
        if (enableSorting) {
            return new TreeSet<IClasspathEntry>(new ClasspathEntryComparator());
        } else {
            return new LinkedHashSet<IClasspathEntry>();
        }
    }

    /**
     * See STS-2054, it is not sufficient to avoid adding duplicates, sometimes gradle
     * adds them and it is nice for us to remove them if it does.
     */
    private void removeDuplicateJREContainers() {
        Collection<IClasspathEntry> entries = getEntries(IClasspathEntry.CPE_CONTAINER);
        Iterator<IClasspathEntry> iterator = entries.iterator();
        IClasspathEntry jreContainer = null;
        while (iterator.hasNext()) {
            IClasspathEntry element = iterator.next();
            if (isJREContainer(element)) {
                if (jreContainer != null) {
                    iterator.remove(); //Already seen a container, so this one is duplicate!
                } else {
                    jreContainer = element;
                }
            }
        }
    }

    /**
     * Retrieves the classpath entries of a particular kind only.
     */
    private Collection<IClasspathEntry> getEntries(int kind) {
        Collection<IClasspathEntry> entries = entryMap.get(kind);
        if (entries == null) {
            entries = createEntrySet(0);
            entryMap.put(kind, entries);
        }
        return entries;
    }

    /**
     * Removes all library entries from this classpath.
     */
    public void removeLibraryEntries() {
        entryMap.remove(IClasspathEntry.CPE_LIBRARY);
    }

    //   private static boolean isLibrary(IClasspathEntry element) {
    //      return element.getEntryKind()==IClasspathEntry.CPE_LIBRARY;
    //   }

    public IClasspathEntry[] toArray() {
        ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>();
        for (int kind : kindOrdering) {
            entries.addAll(getEntries(kind));
        }
        return entries.toArray(new IClasspathEntry[entries.size()]);
    }

    public void add(IClasspathEntry newEntry) {
        int kind = newEntry.getEntryKind();
        Collection<IClasspathEntry> entries = getEntries(kind);
        entries.add(newEntry);
    }

    /**
     * Make sure that a JRE container is present in the classpath. If one is already there, leave it as is.
     * Otherwise add a default one.
     */
    public void ensureJREContainer() {
        removeDuplicateJREContainers(); //STS-2054
        IClasspathEntry currentJREContainer = getContainer(JavaRuntime.JRE_CONTAINER);
        if (currentJREContainer == null) {
            add(JavaRuntime.getDefaultJREContainerEntry());
        }
    }

    /**
     * Find class path container entry with given container ID. If more than one entry 
     * exists the first one found will be returned. If no entry is found null will be
     * returned.
     * 
     * @param containerID
     * @return First matching classpath entry or null if no match.
     */
    public IClasspathEntry getContainer(String containerID) {
        for (IClasspathEntry e : getEntries(IClasspathEntry.CPE_CONTAINER)) {
            Assert.isLegal(e.getEntryKind() == IClasspathEntry.CPE_CONTAINER);
            if (containerID.equals(e.getPath().segment(0))) {
                return e;
            }
        }
        return null;
    }

    public void removeContainer(String containerID) {
        Collection<IClasspathEntry> containers = getEntries(IClasspathEntry.CPE_CONTAINER);
        Iterator<IClasspathEntry> iter = containers.iterator();
        while (iter.hasNext()) {
            IClasspathEntry el = iter.next();
            if (el.getPath().segment(0).equals(containerID)) {
                iter.remove();
            }
        }
    }

    private boolean isJREContainer(IClasspathEntry e) {
        return isContainer(e, JavaRuntime.JRE_CONTAINER);
    }

    private boolean isContainer(IClasspathEntry e, String containerID) {
        return e.getEntryKind() == IClasspathEntry.CPE_CONTAINER && containerID.equals(e.getPath().segment(0));
    }

    /**
     * @param sourceEntries
     */
    public void addAll(List<IClasspathEntry> toAdd) {
        for (IClasspathEntry e : toAdd) {
            add(e);
        }
    }

    /**
     * @param javaProject
     * @param subProgressMonitor
     */
    public void setOn(IJavaProject javaProject, IProgressMonitor mon) throws JavaModelException {
        mon.beginTask("Setting classpath...", 2);
        try {
            IClasspathEntry[] oldClasspath = javaProject.getRawClasspath();
            mon.worked(1);
            IClasspathEntry[] newClasspath = toArray();
            if (isChanged(oldClasspath, newClasspath)) {
                javaProject.setRawClasspath(newClasspath, new SubProgressMonitor(mon, 1));
            }
        } finally {
            mon.done();
        }
    }

    private boolean isChanged(IClasspathEntry[] oldClasspath, IClasspathEntry[] newClasspath) {
        if (oldClasspath.length != newClasspath.length)
            return true;
        for (int i = 0; i < newClasspath.length; i++) {
            if (!oldClasspath[i].equals(newClasspath[i])) {
                return true;
            }
        }
        return false;
    }

    public IClasspathEntry[] getSourceFolders() {
        Collection<IClasspathEntry> entries = getEntries(IClasspathEntry.CPE_SOURCE);
        return entries.toArray(new IClasspathEntry[entries.size()]);
    }

    public IClasspathEntry[] getLibraryEntries() {
        Collection<IClasspathEntry> entries = getEntries(IClasspathEntry.CPE_LIBRARY);
        return entries.toArray(new IClasspathEntry[entries.size()]);
    }

    public IClasspathEntry[] getProjectEntries() {
        Collection<IClasspathEntry> entries = getEntries(IClasspathEntry.CPE_PROJECT);
        return entries.toArray(new IClasspathEntry[entries.size()]);
    }

}