org.eclipse.edt.ide.core.utils.EclipseUtilities.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.edt.ide.core.utils.EclipseUtilities.java

Source

/*******************************************************************************
 * Copyright  2011, 2013 IBM Corporation 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:
 * IBM Corporation - initial API and implementation
 *
 *******************************************************************************/
package org.eclipse.edt.ide.core.utils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.core.externaltools.internal.model.BuilderCoreUtils;
import org.eclipse.core.externaltools.internal.model.ExternalToolBuilder;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
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.edt.gen.EglContext;
import org.eclipse.edt.ide.core.AbstractGenerator;
import org.eclipse.edt.ide.core.CoreIDEPluginStrings;
import org.eclipse.edt.ide.core.EDTCoreIDEPlugin;
import org.eclipse.edt.ide.core.EDTRuntimeContainer;
import org.eclipse.edt.ide.core.IGenerator;
import org.eclipse.edt.ide.core.model.IEGLProject;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jst.j2ee.project.JavaEEProjectUtilities;
import org.eclipse.osgi.util.NLS;

/**
 * Utility methods for working within Eclipse.
 */
@SuppressWarnings("restriction")
public class EclipseUtilities {

    private EclipseUtilities() {
        // No instances.
    }

    /**
     * @return true if the outputFolder represents a folder within the workspace
     */
    public static boolean shouldWriteFileInEclipse(String outputFolder) {
        return !new Path(outputFolder).isAbsolute();
    }

    /**
     * Returns the container in which the file should be written.
     * 
     * @param outputFolder         The folder in which to generate, in the internal folder format (see {@link #convertGenerationDirectoryToPath(String)})
     * @param eglFile              The source file being generated.
     * @param relativeFilePath     The path of the file to be written inside outputFolder. e.g. my/pkg/Foo.java
     * @return the container in which the file should be written.
     * @throws CoreException
     */
    public static IContainer getOutputContainer(String outputFolder, IFile eglFile, String relativeFilePath)
            throws CoreException {
        IContainer container = null;
        IPath outputFolderPath = new Path(convertFromInternalPath(outputFolder));
        int lastSlash = relativeFilePath.lastIndexOf('/');
        if (outputFolderPath.isAbsolute()) {
            IPath path = outputFolderPath;
            if (lastSlash != -1) {
                path = path.append(relativeFilePath.substring(0, lastSlash));
            }

            if (path.segmentCount() > 1) {
                container = ResourcesPlugin.getWorkspace().getRoot().getFolder(path);
                // Verify the containing project exists
                if (!container.getProject().isAccessible()) {
                    throw new CoreException(new Status(IStatus.ERROR, EDTCoreIDEPlugin.PLUGIN_ID,
                            NLS.bind(CoreIDEPluginStrings.ProjectNotAccessible, container.getProject().getName())));
                }
            } else if (path.segmentCount() == 1) {
                container = ResourcesPlugin.getWorkspace().getRoot().getProject(path.segment(0));
                // Projects must exist, we can't just create them like folders
                if (!container.isAccessible()) {
                    throw new CoreException(new Status(IStatus.ERROR, EDTCoreIDEPlugin.PLUGIN_ID,
                            NLS.bind(CoreIDEPluginStrings.ProjectNotAccessible, container.getName())));
                }
            } else {
                throw new CoreException(new Status(IStatus.ERROR, EDTCoreIDEPlugin.PLUGIN_ID,
                        NLS.bind(CoreIDEPluginStrings.CouldNotGetOutputFolder, outputFolderPath)));
            }
        } else {
            // Relative to the source project
            if (lastSlash == -1) {
                container = outputFolderPath.segmentCount() == 0 ? eglFile.getProject()
                        : eglFile.getProject().getFolder(outputFolderPath);
            } else {
                container = eglFile.getProject()
                        .getFolder(outputFolderPath.append(relativeFilePath.substring(0, lastSlash)));
            }
        }

        return container;
    }

    /**
     * Returns the path that should be used for the output file.
     * 
     * @param relativeFilePath     The path of the file to be written inside outputFolder. e.g. my/pkg/Foo.java
     * @return the path that should be used for the output file.
     */
    public static IPath getOutputFilePath(String relativeFilePath) {
        int lastSlash = relativeFilePath.lastIndexOf('/');
        String fileName = lastSlash == -1 ? relativeFilePath : relativeFilePath.substring(lastSlash + 1);
        return new Path(fileName);
    }

    /**
     * Writes a file using Eclipse API, so that the Eclipse filesystem is kept in sync.
     * 
     * @param outputFolder         The folder in which to generate, in the internal folder format (see {@link #convertGenerationDirectoryToPath(String)})
     * @param eglFile              The source file being generated.
     * @param contentsToWrite      The content of the file to write.
     * @param relativeFilePath     The path of the file to be written inside outputFolder. e.g. my/pkg/Foo.java
     * @return the file that was written
     * @throws CoreException
     */
    public static IFile writeFileInEclipse(String outputFolder, IFile eglFile, String contentsToWrite,
            String relativeFilePath) throws CoreException {
        IPath filePath = getOutputFilePath(relativeFilePath);
        IContainer container = getOutputContainer(outputFolder, eglFile, relativeFilePath);
        writeFileInEclipse(container, filePath, EclipseUtilities.getInputStream(eglFile, contentsToWrite), true);
        return container.getFile(filePath);
    }

    /**
     * Returns a handle to the generated output file for the given path.
     * 
     * @param outputFolder         The folder in which to generate, in the internal folder format (see {@link #convertGenerationDirectoryToPath(String)})
     * @param eglFile              The source file being generated.
     * @param relativeFilePath     The path of the file to be written inside outputFolder. e.g. my/pkg/Foo.java
     * @return a handle to the generated output file for the given path.
     * @throws CoreException
     */
    public static IFile getOutputFile(String outputFolder, IFile eglFile, String relativeFilePath)
            throws CoreException {
        IPath filePath = getOutputFilePath(relativeFilePath);
        IContainer container = getOutputContainer(outputFolder, eglFile, relativeFilePath);
        return container.getFile(filePath);
    }

    /**
     * Writes a file using Eclipse API, so that the Eclipse filesystem is kept in sync. The input stream will be closed before the method returns.
     * 
     * @param outputContainer           The location in which to write the file.
     * @param fileName                  The name of the file to write.
     * @param contents                  The contents to write to the file.
     * @param createFoldersIfNecessary  Flag indicating if we should create parent folders if they don't already exist.
     * @throws CoreException 
     */
    public static void writeFileInEclipse(IContainer outputContainer, IPath fileName, InputStream dataStream,
            boolean createFoldersIfNecessary) throws CoreException {
        try {
            if (createFoldersIfNecessary && outputContainer instanceof IFolder) {
                createFolder((IFolder) outputContainer);
            }

            IFile outputFile = outputContainer.getFile(fileName);
            if (outputFile.exists()) {
                outputFile.setContents(dataStream, true, false, null);
            } else {
                outputFile.create(dataStream, IResource.FORCE, null);
            }
        } finally {
            if (dataStream != null) {
                try {
                    dataStream.close();
                } catch (IOException e) {
                }
            }
        }
    }

    /**
     * Creates the folder and its parents if they don't already exist.
     * 
     * @param folder  The folder to create.
     * @throws CoreException
     */
    public static void createFolder(IFolder folder) throws CoreException {
        if (!folder.exists()) {
            IContainer parent = folder.getParent();
            if (parent instanceof IFolder) {
                createFolder((IFolder) parent);
            }
            folder.create(true, true, null);
            folder.setDerived(true, null);
        }
    }

    /**
     * Creates an InputStream for the data, attempting to use the charset of the source file, if available.
     * 
     * @param sourceFile  The source file from which to get the charset (may be null).
     * @param data        The data the input stream will write.
     * @return an InputStream for the data, attempting to use the charset of the source file, if available.
     */
    public static InputStream getInputStream(IFile sourceFile, String data) {
        if (sourceFile != null) {
            try {
                String encoding = sourceFile.getCharset();
                if (encoding != null) {
                    try {
                        return new ByteArrayInputStream(data.getBytes(encoding));
                    } catch (UnsupportedEncodingException e) {
                    }
                }
            } catch (CoreException e) {
            }
        }
        return new ByteArrayInputStream(data.getBytes());
    }

    /**
     * Adds the outputFolder as a Java source folder if the project is a Java project.
     * 
     * @param project       The project containing the folder (used when outputFolder is a relative path)
     * @param outputFolder  The path of the folder. It may be project-relative, or workspace-relative. If workspace-relative
     *                      it should start with 'F/' for a folder or 'P/' for a project.
     * @param forceClasspathRefresh A classpath needs to be refreshed if an entry already exists for the output folder, but the folder has yet to be
     *                         created.  This can occur when a project is exported without a generation directory.
     * @throws CoreException
     */
    public static void addToJavaBuildPathIfNecessary(IProject project, String outputFolder,
            boolean forceClasspathRefresh) throws CoreException {
        if (project.hasNature(JavaCore.NATURE_ID)) {
            IJavaProject javaProject = JavaCore.create(project);
            if (javaProject.exists()) {
                IClasspathEntry[] entries = javaProject.getRawClasspath();
                IPath outputFolderPath = new Path(convertFromInternalPath(outputFolder));
                boolean needToAdd = true;

                IPath fullPath = outputFolderPath.isAbsolute() ? outputFolderPath
                        : outputFolderPath.segmentCount() == 0 ? project.getFullPath()
                                : project.getFolder(outputFolderPath).getFullPath();

                for (int i = 0; i < entries.length; i++) {
                    if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                        IPath nextPath = entries[i].getPath();
                        // JDT throws an error if you have a source folder within a source folder. We could add exclusions to support this, but
                        // for now we just won't add the folder.
                        if (nextPath.isPrefixOf(fullPath) || fullPath.isPrefixOf(nextPath)) {
                            needToAdd = false;
                            break;
                        }
                    }
                }

                if (needToAdd) {
                    IClasspathEntry[] newEntries = new IClasspathEntry[entries.length + 1];
                    System.arraycopy(entries, 0, newEntries, 0, entries.length);
                    newEntries[newEntries.length - 1] = JavaCore.newSourceEntry(fullPath);
                    javaProject.setRawClasspath(newEntries, null);
                }

                if (!needToAdd && forceClasspathRefresh) {
                    javaProject.setRawClasspath(javaProject.readRawClasspath(), javaProject.readOutputLocation(),
                            null);
                }
            }
        }
    }

    /**
     * Returns a path representing the generation directory, which may be worspace- or project-relative. An internal
     * convention is used for paths and this routine will normalize it to be of the format "/myproject/my/folder" for
     * workspace-relative paths and "my/folder" for project-relative paths. A blank string is returned for "this project".
     * 
     * @param path  The internal representation of the generation directory path
     * @return the normalized generation directory path
     */
    public static String convertFromInternalPath(String path) {
        // We prefix workspace-relative paths with W/, project-relative paths with P/.
        if (path.startsWith("W/")) { //$NON-NLS-1$
            return path.substring(1);
        } else if (path.startsWith("P/")) { //$NON-NLS-1$
            return path.substring(2);
        }
        return path;
    }

    public static String convertToInternalPath(String path) {
        if (path.startsWith("/")) { //$NON-NLS-1$
            return "W" + path; //$NON-NLS-1$
        }
        return "P/" + path; //$NON-NLS-1$
    }

    /**
     * Adds the runtime containers to the project if necessary. This does nothing if the project is
     * not a Java project.
     * 
     * @param project   The Java project.
     * @param generator  The generator provider.
     * @param ctx  The generation context.
     */
    public static void addRuntimesToProject(IProject project, IGenerator generator, EglContext ctx) {
        EDTRuntimeContainer[] baseRuntimes = generator instanceof AbstractGenerator
                ? ((AbstractGenerator) generator).resolveBaseRuntimeContainers()
                : null;

        EDTRuntimeContainer[] containersToAdd;
        Set<String> requiredContainers = ctx.getRequiredRuntimeContainers();
        if (requiredContainers.size() == 0) {
            if (baseRuntimes == null || baseRuntimes.length == 0) {
                return;
            }
            containersToAdd = baseRuntimes;
        } else {
            Set<EDTRuntimeContainer> containers = new HashSet<EDTRuntimeContainer>(10);
            if (baseRuntimes != null && baseRuntimes.length > 0) {
                containers.addAll(Arrays.asList(baseRuntimes));
            }
            for (EDTRuntimeContainer container : generator.getRuntimeContainers()) {
                if (requiredContainers.contains(container.getId())) {
                    containers.add(container);
                }
            }
            containersToAdd = containers.toArray(new EDTRuntimeContainer[containers.size()]);
        }

        if (containersToAdd == null || containersToAdd.length == 0) {
            return;
        }

        try {
            if (project.hasNature(JavaCore.NATURE_ID)) {
                IJavaProject javaProject = JavaCore.create(project);
                IClasspathEntry[] classpath = javaProject.getRawClasspath();

                List<IClasspathEntry> additions = new ArrayList<IClasspathEntry>();

                for (int i = 0; i < containersToAdd.length; i++) {
                    IPath path = containersToAdd[i].getPath();
                    boolean found = false;
                    for (int j = 0; j < classpath.length; j++) {
                        if (classpath[j].getEntryKind() == IClasspathEntry.CPE_CONTAINER
                                && classpath[j].getPath().equals(path)) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        additions.add(JavaCore.newContainerEntry(path));
                    }
                }

                if (additions.size() > 0) {
                    IClasspathEntry[] newEntries = new IClasspathEntry[classpath.length + additions.size()];
                    System.arraycopy(classpath, 0, newEntries, 0, classpath.length);
                    for (int i = 0; i < additions.size(); i++) {
                        newEntries[classpath.length + i] = additions.get(i);
                    }
                    javaProject.setRawClasspath(newEntries, null);
                }
            }
        } catch (CoreException e) {
            EDTCoreIDEPlugin.log(e);
        }
    }

    /**
     * Adds the SMAP builder to the project if necessary. This does nothing if the project is not a Java project.
     * @param project  The Java project.
     */
    public static void addSMAPBuilder(IProject project) {
        try {
            if (project.hasNature(JavaCore.NATURE_ID)) {
                String builderID = "org.eclipse.edt.debug.core.smapBuilder";
                IProjectDescription description = project.getDescription();

                ICommand smapCommand = null;
                ICommand[] commands = description.getBuildSpec();
                for (ICommand command : commands) {
                    if (command.getBuilderName().equals(builderID)) {
                        smapCommand = command;
                        break;
                    }
                    // Disabled builders become "external tool builders"
                    else if (ExternalToolBuilder.ID.equals(command.getBuilderName())) {
                        Object attr = command.getArguments().get(BuilderCoreUtils.LAUNCH_CONFIG_HANDLE);
                        if (attr instanceof String && ((String) attr).contains(builderID)) {
                            smapCommand = command;
                            break;
                        }
                    }
                }

                if (smapCommand == null) {
                    smapCommand = description.newCommand();
                    smapCommand.setBuilderName(builderID);

                    ICommand[] newCommands = new ICommand[commands.length + 1];
                    System.arraycopy(commands, 0, newCommands, 0, commands.length);
                    newCommands[commands.length] = smapCommand;

                    description.setBuildSpec(newCommands);
                    project.setDescription(description, null);
                }
            }
        } catch (CoreException e) {
            EDTCoreIDEPlugin.log(e);
        }
    }

    /**
     * Returns true if this project is a J2EE web project. Returns false if this
     * is not a web project or is a static web project.
     * 
     * @param project
     *            Project
     * @return boolean
     */
    public static boolean isWebProject(IProject project) {
        return JavaEEProjectUtilities.isDynamicWebProject(project);
    }

    /**
     * Get the source folder name. For new Java projects, check the source
     * folder name in the Java Build Path preferences. For all types of Java
     * projects, use the first source folder from the classpath.
     * 
     * @param myProject
     *            The project where the folder for Java source resides.
     * 
     * @return String The Java source folder name.
     */
    public static String getJavaSourceFolderName(IProject project) {
        String folderName = null;

        try {
            if (project.hasNature(JavaCore.NATURE_ID)) {
                // Use the first folder from the project's classpath. 
                IJavaProject javaProject = JavaCore.create(project);
                IClasspathEntry[] entries = javaProject.getRawClasspath();
                for (int i = 0; i < entries.length; i++) {
                    IClasspathEntry entry = entries[i];
                    if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                        // Get the folder from the entry's path.  The project name
                        // needs to be removed from the path before this will work.
                        IPath path = entry.getPath().removeFirstSegments(1);
                        return path.toString();
                    }
                }
            }
        } catch (Exception e) {
        }
        return folderName;
    }

    public static List<String> getDependentDescriptors(IProject project) throws Exception {
        List eglProjectPath = org.eclipse.edt.ide.core.internal.utils.Util.getEGLProjectPath(project);

        final List<String> egldds = new ArrayList<String>();
        for (Iterator<IEGLProject> iter1 = eglProjectPath.iterator(); iter1.hasNext();) {
            IEGLProject eglProject = iter1.next();
            IProject dependentPro = eglProject.getProject();
            final IPath outputPath = eglProject.getOutputLocation();
            dependentPro.accept(new IResourceVisitor() {
                @Override
                public boolean visit(IResource resource) throws CoreException {
                    if (outputPath.isPrefixOf(resource.getFullPath())) {
                        if (resource instanceof IFile && "egldd".equals(resource.getFileExtension())) {
                            try {
                                egldds.add(resource.getFullPath().toString());
                            } catch (Exception e) {
                            }
                            return false;
                        }
                    }
                    return resource.getFullPath().isPrefixOf(outputPath);
                }
            });
        }

        return egldds;
    }
}