/* * Copyright (c) 2014, the Dart project authors. * * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html * * 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.dart.tools.core.internal.analysis.model; import com.google.dart.server.AnalysisServerListener; import com.google.dart.tools.core.DartCore; import com.google.dart.tools.core.internal.builder.AnalysisMarkerManager_NEW; import com.google.dart.tools.core.internal.util.ResourceUtil; import com.google.dart.tools.core.utilities.io.PrintStringWriter; import org.dartlang.analysis.server.protocol.AnalysisError; import org.dartlang.analysis.server.protocol.AnalysisStatus; import org.dartlang.analysis.server.protocol.CompletionSuggestion; import org.dartlang.analysis.server.protocol.HighlightRegion; import org.dartlang.analysis.server.protocol.ImplementedClass; import org.dartlang.analysis.server.protocol.ImplementedMember; import org.dartlang.analysis.server.protocol.NavigationRegion; import org.dartlang.analysis.server.protocol.Occurrences; import org.dartlang.analysis.server.protocol.Outline; import org.dartlang.analysis.server.protocol.OverrideMember; import org.dartlang.analysis.server.protocol.PubStatus; import org.dartlang.analysis.server.protocol.RequestError; import org.dartlang.analysis.server.protocol.RequestErrorCode; import org.dartlang.analysis.server.protocol.SearchResult; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import java.io.File; import java.util.List; /** * Implementation of {@link AnalysisServerListener} for the Eclipse workspace. */ public class WorkspaceAnalysisServerListener implements AnalysisServerListener { private final AnalysisServerDataImpl dataImpl; private final DartProjectManager projectManager; private final Object statusLock = new Object(); private boolean serverBusy = false; private Job statusJob; public WorkspaceAnalysisServerListener(AnalysisServerDataImpl dataImpl, DartProjectManager projectManager) { this.dataImpl = dataImpl; this.projectManager = projectManager; } @Override public void computedAnalyzedFiles(List<String> directories) { } @Override public void computedCompletion(String completionId, int replacementOffset, int replacementLength, List<CompletionSuggestion> completions, boolean isLast) { // TODO(jwren/scheglov) not yet implemented } @Override public void computedErrors(String filePath, List<AnalysisError> errors) { AnalysisError[] errorsArray = errors.toArray(new AnalysisError[errors.size()]); dataImpl.internalComputedErrors(filePath, errorsArray); scheduleResourceErrorMarkersUpdate(filePath, errorsArray); } @Override public void computedHighlights(String file, List<HighlightRegion> highlights) { HighlightRegion[] highlightsArray = highlights.toArray(new HighlightRegion[highlights.size()]); dataImpl.internalComputedHighlights(file, highlightsArray); } @Override public void computedImplemented(String file, List<ImplementedClass> implementedClasses, List<ImplementedMember> implementedMembers) { // TODO(scheglov) not yet implemented } @Override public void computedLaunchData(String file, String kind, String[] referencedFiles) { dataImpl.internalComputedLaunchData(file, kind, referencedFiles); } @Override public void computedNavigation(String file, List<NavigationRegion> targets) { NavigationRegion[] targetsArray = targets.toArray(new NavigationRegion[targets.size()]); dataImpl.internalComputedNavigation(file, targetsArray); } @Override public void computedOccurrences(String file, List<Occurrences> occurrences) { Occurrences[] occurrencesArray = occurrences.toArray(new Occurrences[occurrences.size()]); dataImpl.internalComputedOccurrences(file, occurrencesArray); } @Override public void computedOutline(String file, Outline outline) { dataImpl.internalComputedOutline(file, outline); } @Override public void computedOverrides(String file, List<OverrideMember> overrideMember) { OverrideMember[] overridesArray = overrideMember.toArray(new OverrideMember[overrideMember.size()]); dataImpl.internalComputedOverrides(file, overridesArray); } @Override public void computedSearchResults(String searchId, List<SearchResult> results, boolean last) { dataImpl.internalComputedSearchResults(searchId, results, last); } @Override public void flushedResults(List<String> files) { // clear information dataImpl.internalFlushResults(files); // remove markers for (String file : files) { scheduleResourceErrorMarkersUpdate(file, AnalysisError.EMPTY_ARRAY); } } @Override public void requestError(RequestError requestError) { String errorCode = requestError.getCode(); if (RequestErrorCode.SERVER_ERROR.equals(errorCode)) { DartCore.logRequestError(requestError); } } @Override public void serverConnected(String version) { projectManager.start(); } @Override public void serverError(boolean isFatal, String message, String stackTrace) { @SuppressWarnings("resource") PrintStringWriter buf = new PrintStringWriter(); buf.println("ServerError: Fatal=" + isFatal); buf.println(message); buf.println(stackTrace); DartCore.logError(buf.toString()); } @Override public void serverIncompatibleVersion(String version) { // TODO(scheglov) not yet implemented } @Override public void serverStatus(AnalysisStatus analysisStatus, PubStatus pubStatus) { dataImpl.internalServerStatus(analysisStatus); String statusMessage = getStatus(analysisStatus, pubStatus); synchronized (statusLock) { if (statusMessage != null) { serverBusy = true; if (statusJob == null) { // // Start a build level job to display progress in the status area. // statusJob = new Job(statusMessage) { @Override protected IStatus run(IProgressMonitor monitor) { waitUntilServerIdle(); return Status.OK_STATUS; } }; statusJob.setPriority(Job.BUILD); statusJob.schedule(); } else { statusJob.setName(statusMessage); } } else { if (statusJob != null) { // // Signal the status job to exit. // serverBusy = false; statusLock.notifyAll(); } } } } /** * Return the status message that should be displayed given the analysis and pub status objects, * or {@code null} if there is no status message to be displayed. * * @param analysisStatus the current analysis status of the server, or {@code null} if there is no * analysis status * @param pubStatus the current pub status of the server, or {@code null} if there is no pub * status * @return the status message that should be displayed */ private String getStatus(AnalysisStatus analysisStatus, PubStatus pubStatus) { if (pubStatus != null && pubStatus.isListingPackageDirs()) { return "Running pub..."; } else if (analysisStatus != null && analysisStatus.isAnalyzing()) { return "Analyzing..."; } return null; } private void scheduleResourceErrorMarkersUpdate(String filePath, AnalysisError[] errors) { File file = new File(filePath); if (file.exists()) { IResource resource = ResourceUtil.getResource(file); if (resource != null) { AnalysisMarkerManager_NEW.getInstance().queueErrors(resource, errors); } } } private void waitUntilServerIdle() { synchronized (statusLock) { while (serverBusy) { try { statusLock.wait(3000); } catch (InterruptedException e) { //$FALL-THROUGH$ } } statusJob = null; } } }