com.google.cloud.tools.eclipse.appengine.libraries.repository.LibraryClasspathContainerResolverService.java Source code

Java tutorial

Introduction

Here is the source code for com.google.cloud.tools.eclipse.appengine.libraries.repository.LibraryClasspathContainerResolverService.java

Source

/*
 * Copyright 2016 Google Inc.
 *
 * Licensed under 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.
 */

package com.google.cloud.tools.eclipse.appengine.libraries.repository;

import com.google.cloud.tools.eclipse.appengine.libraries.AppEngineLibraries;
import com.google.cloud.tools.eclipse.appengine.libraries.ILibraryClasspathContainerResolverService;
import com.google.cloud.tools.eclipse.appengine.libraries.LibraryClasspathContainer;
import com.google.cloud.tools.eclipse.appengine.libraries.Messages;
import com.google.cloud.tools.eclipse.appengine.libraries.SourceAttacherJob;
import com.google.cloud.tools.eclipse.appengine.libraries.model.Filter;
import com.google.cloud.tools.eclipse.appengine.libraries.model.Library;
import com.google.cloud.tools.eclipse.appengine.libraries.model.LibraryFile;
import com.google.cloud.tools.eclipse.appengine.libraries.persistence.LibraryClasspathContainerSerializer;
import com.google.cloud.tools.eclipse.util.status.StatusUtil;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import org.apache.maven.artifact.Artifact;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IAccessRule;
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.jst.j2ee.classpathdep.UpdateClasspathAttributeUtil;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

@Component
public class LibraryClasspathContainerResolverService implements ILibraryClasspathContainerResolverService {

    private static final String CLASSPATH_ATTRIBUTE_SOURCE_URL = "com.google.cloud.tools.eclipse.appengine.libraries.sourceUrl";

    private ILibraryRepositoryService repositoryService;
    private LibraryClasspathContainerSerializer serializer;

    public IStatus resolveAll(IJavaProject javaProject, IProgressMonitor monitor) {
        IStatus status = null;
        try {
            IClasspathEntry[] rawClasspath = javaProject.getRawClasspath();
            SubMonitor subMonitor = SubMonitor.convert(monitor, Messages.getString("TaskResolveLibraries"),
                    getTotalwork(rawClasspath));
            for (IClasspathEntry classpathEntry : rawClasspath) {
                if (classpathEntry.getPath().segment(0).equals(Library.CONTAINER_PATH_PREFIX)) {
                    status = StatusUtil.merge(status,
                            resolveContainer(javaProject, classpathEntry.getPath(), subMonitor.newChild(1)));
                }
            }
        } catch (CoreException ex) {
            return StatusUtil.error(this, Messages.getString("TaskResolveLibrariesError"), ex);
        }
        return status == null ? Status.OK_STATUS : status;
    }

    public IClasspathEntry[] resolveLibraryAttachSourcesSync(String libraryId) throws CoreException {
        Library library = AppEngineLibraries.getLibrary(libraryId);
        if (library != null) {
            IClasspathEntry[] resolvedEntries = new IClasspathEntry[library.getLibraryFiles().size()];
            int idx = 0;
            for (LibraryFile libraryFile : library.getLibraryFiles()) {
                resolvedEntries[idx++] = resolveLibraryFileAttachSourceSync(libraryFile);
            }
            return resolvedEntries;
        } else {
            throw new CoreException(StatusUtil.error(this, Messages.getString("InvalidLibraryId", libraryId)));
        }
    }

    public IStatus resolveContainer(IJavaProject javaProject, IPath containerPath, IProgressMonitor monitor) {
        Preconditions.checkArgument(containerPath.segment(0).equals(Library.CONTAINER_PATH_PREFIX));
        try {
            String libraryId = containerPath.segment(1);
            Library library = AppEngineLibraries.getLibrary(libraryId);
            if (library != null) {
                List<Job> sourceAttacherJobs = new ArrayList<>();
                LibraryClasspathContainer container = resolveLibraryFiles(javaProject, containerPath, library,
                        sourceAttacherJobs, monitor);
                JavaCore.setClasspathContainer(containerPath, new IJavaProject[] { javaProject },
                        new IClasspathContainer[] { container }, new NullProgressMonitor());
                serializer.saveContainer(javaProject, container);
                for (Job job : sourceAttacherJobs) {
                    job.schedule();
                }
            }
            return Status.OK_STATUS;
        } catch (CoreException | IOException ex) {
            return StatusUtil.error(this, Messages.getString("TaskResolveContainerError", containerPath), ex);
        }
    }

    public IStatus checkRuntimeAvailability(AppEngineRuntime runtime, IProgressMonitor monitor) {
        switch (runtime) {
        case STANDARD_JAVA_7:
            return checkAppEngineStandardJava7(monitor);
        default:
            throw new IllegalArgumentException("Unhandled runtime: " + runtime);
        }
    }

    private IStatus checkAppEngineStandardJava7(IProgressMonitor monitor) {
        try {
            for (String libraryId : new String[] { "servlet-api", "jsp-api" }) {
                Library library = AppEngineLibraries.getLibrary(libraryId);
                for (LibraryFile libraryFile : library.getLibraryFiles()) {
                    if (monitor.isCanceled()) {
                        return Status.CANCEL_STATUS;
                    }
                    repositoryService.makeArtifactAvailable(libraryFile, monitor);
                }
            }
            return Status.OK_STATUS;
        } catch (CoreException ex) {
            return StatusUtil.error(this, Messages.getString("LibraryUnavailable"), ex);
        }
    }

    private LibraryClasspathContainer resolveLibraryFiles(IJavaProject javaProject, IPath containerPath,
            Library library, List<Job> sourceAttacherJobs, IProgressMonitor monitor) throws CoreException {
        List<LibraryFile> libraryFiles = library.getLibraryFiles();
        SubMonitor subMonitor = SubMonitor.convert(monitor, libraryFiles.size());
        subMonitor.subTask(Messages.getString("TaskResolveArtifacts", getLibraryDescription(library)));
        SubMonitor child = subMonitor.newChild(libraryFiles.size());

        IClasspathEntry[] entries = new IClasspathEntry[libraryFiles.size()];
        int idx = 0;
        for (final LibraryFile libraryFile : libraryFiles) {
            IClasspathEntry newLibraryEntry = resolveLibraryFileAttachSourceAsync(javaProject, containerPath,
                    libraryFile, sourceAttacherJobs, monitor);
            entries[idx++] = newLibraryEntry;
            child.worked(1);
        }
        monitor.done();
        LibraryClasspathContainer container = new LibraryClasspathContainer(containerPath,
                getLibraryDescription(library), entries);
        return container;
    }

    private IClasspathEntry resolveLibraryFileAttachSourceAsync(IJavaProject javaProject, IPath containerPath,
            LibraryFile libraryFile, List<Job> sourceAttacherJobs, IProgressMonitor monitor) throws CoreException {
        Artifact artifact = repositoryService.resolveArtifact(libraryFile, monitor);
        IPath libraryPath = new Path(artifact.getFile().getAbsolutePath());
        IPath sourceAttachmentPath = null;
        Job job = createSourceAttacherJob(javaProject, containerPath, libraryFile, monitor, artifact, libraryPath);
        sourceAttacherJobs.add(job);
        IClasspathEntry newLibraryEntry = JavaCore.newLibraryEntry(libraryPath, sourceAttachmentPath,
                null /*  sourceAttachmentRootPath */, getAccessRules(libraryFile.getFilters()),
                getClasspathAttributes(libraryFile, artifact), true /* isExported */);
        return newLibraryEntry;
    }

    private SourceAttacherJob createSourceAttacherJob(IJavaProject javaProject, IPath containerPath,
            final LibraryFile libraryFile, final IProgressMonitor monitor, final Artifact artifact,
            IPath libraryPath) {
        return new SourceAttacherJob(javaProject, containerPath, libraryPath, new Callable<IPath>() {
            @Override
            public IPath call() throws Exception {
                return repositoryService.resolveSourceArtifact(libraryFile, artifact.getVersion(), monitor);
            }
        });
    }

    private IClasspathEntry resolveLibraryFileAttachSourceSync(final LibraryFile libraryFile) throws CoreException {

        final Artifact artifact = repositoryService.resolveArtifact(libraryFile, new NullProgressMonitor());
        IPath libraryPath = new Path(artifact.getFile().getAbsolutePath());
        IPath sourceAttachmentPath = null;
        sourceAttachmentPath = repositoryService.resolveSourceArtifact(libraryFile, artifact.getVersion(),
                new NullProgressMonitor());
        final IClasspathEntry newLibraryEntry = JavaCore.newLibraryEntry(libraryPath, sourceAttachmentPath,
                null /*  sourceAttachmentRootPath */, getAccessRules(libraryFile.getFilters()),
                getClasspathAttributes(libraryFile, artifact), true /* isExported */);
        return newLibraryEntry;

    }

    private static int getTotalwork(IClasspathEntry[] rawClasspath) {
        int sum = 0;
        for (IClasspathEntry element : rawClasspath) {
            if (isLibraryClasspathEntry(element.getPath())) {
                ++sum;
            }
        }
        return sum;
    }

    private static boolean isLibraryClasspathEntry(IPath path) {
        return path != null && path.segmentCount() == 2 && Library.CONTAINER_PATH_PREFIX.equals(path.segment(0));
    }

    private static String getLibraryDescription(Library library) {
        if (!Strings.isNullOrEmpty(library.getName())) {
            return library.getName();
        } else {
            return library.getId();
        }
    }

    @Activate
    protected void initialize() {
        serializer = new LibraryClasspathContainerSerializer();
    }

    private static IAccessRule[] getAccessRules(List<Filter> filters) {
        IAccessRule[] accessRules = new IAccessRule[filters.size()];
        int idx = 0;
        for (Filter filter : filters) {
            int accessRuleKind = filter.isExclude() ? IAccessRule.K_NON_ACCESSIBLE : IAccessRule.K_ACCESSIBLE;
            accessRules[idx++] = JavaCore.newAccessRule(new Path(filter.getPattern()), accessRuleKind);
        }
        return accessRules;
    }

    private static IClasspathAttribute[] getClasspathAttributes(LibraryFile libraryFile, Artifact artifact)
            throws CoreException {
        List<IClasspathAttribute> attributes = MavenCoordinatesHelper
                .createClasspathAttributes(libraryFile.getMavenCoordinates(), artifact.getVersion());
        if (libraryFile.isExport()) {
            attributes.add(UpdateClasspathAttributeUtil.createDependencyAttribute(true /* isWebApp */));
        } else {
            attributes.add(UpdateClasspathAttributeUtil.createNonDependencyAttribute());
        }
        if (libraryFile.getSourceUri() != null) {
            addUriAttribute(attributes, CLASSPATH_ATTRIBUTE_SOURCE_URL, libraryFile.getSourceUri());
        }
        if (libraryFile.getJavadocUri() != null) {
            addUriAttribute(attributes, IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME,
                    libraryFile.getJavadocUri());
        }
        return attributes.toArray(new IClasspathAttribute[0]);
    }

    private static void addUriAttribute(List<IClasspathAttribute> attributes, String attributeName, URI uri) {
        try {
            attributes.add(JavaCore.newClasspathAttribute(attributeName, uri.toURL().toString()));
        } catch (MalformedURLException | IllegalArgumentException ex) {
            // disregard invalid URL
        }
    }

    @Reference
    public void setRepositoryService(ILibraryRepositoryService repositoryService) {
        this.repositoryService = repositoryService;
    }

    public void unsetRepositoryService(ILibraryRepositoryService repositoryService) {
        if (this.repositoryService == repositoryService) {
            this.repositoryService = null;
        }
    }

}