GoogleCloudPlatform / google-cloud-eclipse

Google Cloud Platform plugin for Eclipse
Apache License 2.0
86 stars 49 forks source link

ResourceException during LibraryClasspathContainer initialization #3181

Open briandealwis opened 6 years ago

briandealwis commented 6 years ago

As a follow-on to #3180, I noticed the following exception being logged.

Jun 26, 2018 1:32:02 PM com.google.cloud.tools.eclipse.appengine.libraries.repository.LibraryClasspathContainerResolverService resolveContainer
SEVERE: Could not resolve container: com.google.cloud.tools.eclipse.appengine.libraries/appengine-api
org.eclipse.core.internal.resources.ResourceException: The resource tree is locked for modifications.
    at org.eclipse.core.internal.resources.WorkManager.checkIn(WorkManager.java:119)
    at org.eclipse.core.internal.resources.Workspace.prepareOperation(Workspace.java:2188)
    at org.eclipse.core.internal.resources.Folder.create(Folder.java:90)
    at org.eclipse.core.internal.resources.Folder.create(Folder.java:121)
    at com.google.cloud.tools.eclipse.appengine.libraries.persistence.LibraryClasspathContainerSerializer$DefaultStateLocationProvider.getFile(LibraryClasspathContainerSerializer.java:215)
    at com.google.cloud.tools.eclipse.appengine.libraries.persistence.LibraryClasspathContainerSerializer$DefaultStateLocationProvider.getContainerStateFile(LibraryClasspathContainerSerializer.java:202)
    at com.google.cloud.tools.eclipse.appengine.libraries.persistence.LibraryClasspathContainerSerializer.getContainerStateFile(LibraryClasspathContainerSerializer.java:184)
    at com.google.cloud.tools.eclipse.appengine.libraries.persistence.LibraryClasspathContainerSerializer.saveContainer(LibraryClasspathContainerSerializer.java:87)
    at com.google.cloud.tools.eclipse.appengine.libraries.repository.LibraryClasspathContainerResolverService.resolveContainer(LibraryClasspathContainerResolverService.java:173)
    at com.google.cloud.tools.eclipse.appengine.libraries.LibraryClasspathContainerInitializer.initialize(LibraryClasspathContainerInitializer.java:86)
    at org.eclipse.jdt.internal.core.JavaModelManager.initializeContainer(JavaModelManager.java:3114)
    at org.eclipse.jdt.internal.core.JavaModelManager$10.run(JavaModelManager.java:3020)
    at org.eclipse.jdt.internal.core.JavaModelManager.initializeAllContainers(JavaModelManager.java:3058)
    at org.eclipse.jdt.internal.core.JavaModelManager.getClasspathContainer(JavaModelManager.java:2058)
    at org.eclipse.jdt.core.JavaCore.getClasspathContainer(JavaCore.java:3568)
    at org.eclipse.jdt.internal.core.JavaProject.resolveClasspath(JavaProject.java:2986)
    at org.eclipse.jdt.internal.core.JavaProject.resolveClasspath(JavaProject.java:3150)
    at org.eclipse.jdt.internal.core.JavaProject.getResolvedClasspath(JavaProject.java:2255)
    at org.eclipse.jdt.internal.core.DeltaProcessingState.getRootInfos(DeltaProcessingState.java:310)
    at org.eclipse.jdt.internal.core.DeltaProcessingState.initializeRoots(DeltaProcessingState.java:255)
    at org.eclipse.jdt.internal.core.DeltaProcessor.processResourceDelta(DeltaProcessor.java:1926)
    at org.eclipse.jdt.internal.core.DeltaProcessor.resourceChanged(DeltaProcessor.java:2128)
    at org.eclipse.jdt.internal.core.DeltaProcessingState.resourceChanged(DeltaProcessingState.java:473)
    at org.eclipse.core.internal.events.NotificationManager$1.run(NotificationManager.java:299)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.core.internal.events.NotificationManager.notify(NotificationManager.java:289)
    at org.eclipse.core.internal.events.NotificationManager.broadcastChanges(NotificationManager.java:152)
    at org.eclipse.core.internal.resources.Workspace.broadcastPostChange(Workspace.java:374)
    at org.eclipse.core.internal.resources.Workspace.endOperation(Workspace.java:1469)
    at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2253)
    at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2267)
    at org.eclipse.ui.actions.WorkspaceModifyOperation.run(WorkspaceModifyOperation.java:128)
    at org.eclipse.jface.operation.ModalContext$ModalContextThread.run(ModalContext.java:119)

This occurs in the following code:

        JavaCore.setClasspathContainer(
            containerPath,
            new IJavaProject[] {javaProject},
            new IClasspathContainer[] {container},
            subMonitor.newChild(1));
        serializer.saveContainer(javaProject, container);
        for (Job job : sourceAttacherJobs) {
          job.schedule();
        }

We haven't noticed this problem previously because the classpath container was successfully resolved and set on the project.

briandealwis commented 6 years ago

I should note that this occurred during the upgrading process as part of ImportNativeAppEngineStandardProjectTest where we coalesce our older containers into the new single master container.

I don't know that we can detect this situation. There are two solutions that I can think of:

  1. Wrap the saveContainer() within a try-catch, with the expectation that the container will be re-resolved in another situation (i.e., outside of a workspace notification) and so be able to write out the serialized container state.

  2. Punt the container state serialization to a job. The danger is that we might might modify the container definition in the meantime so that the job would write out stale data.

briandealwis commented 6 years ago

Oops, wasn't finished. I should note that we've been doing (1) implicitly since we were silently swallowing the exception.

chanseokoh commented 6 years ago

If the container is expected to be resolved eventually or frequently enough, I think (1) isn't a bad idea (also considering we've been doing so)?