/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* 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:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.ext.java.client.editor;
import com.google.common.base.Optional;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import org.eclipse.che.ide.api.editor.EditorWithErrors;
import org.eclipse.che.ide.api.editor.annotation.AnnotationModel;
import org.eclipse.che.ide.api.editor.document.Document;
import org.eclipse.che.ide.api.editor.reconciler.DirtyRegion;
import org.eclipse.che.ide.api.editor.reconciler.ReconcilingStrategy;
import org.eclipse.che.ide.api.editor.text.Region;
import org.eclipse.che.ide.api.editor.texteditor.TextEditor;
import org.eclipse.che.ide.api.resources.Project;
import org.eclipse.che.ide.api.resources.Resource;
import org.eclipse.che.ide.api.resources.VirtualFile;
import org.eclipse.che.ide.ext.java.client.JavaLocalizationConstant;
import org.eclipse.che.ide.ext.java.client.util.JavaUtil;
import org.eclipse.che.ide.ext.java.shared.dto.HighlightedPosition;
import org.eclipse.che.ide.ext.java.shared.dto.Problem;
import org.eclipse.che.ide.ext.java.shared.dto.ReconcileResult;
import org.eclipse.che.ide.project.ResolvingProjectStateHolder;
import org.eclipse.che.ide.project.ResolvingProjectStateHolder.ResolvingProjectState;
import org.eclipse.che.ide.project.ResolvingProjectStateHolder.ResolvingProjectStateListener;
import org.eclipse.che.ide.project.ResolvingProjectStateHolderRegistry;
import org.eclipse.che.ide.util.loging.Log;
import javax.validation.constraints.NotNull;
import java.util.Collections;
import java.util.List;
import static org.eclipse.che.ide.project.ResolvingProjectStateHolder.ResolvingProjectState.IN_PROGRESS;
public class JavaReconcilerStrategy implements ReconcilingStrategy, ResolvingProjectStateListener {
private final TextEditor editor;
private final JavaCodeAssistProcessor codeAssistProcessor;
private final AnnotationModel annotationModel;
private final SemanticHighlightRenderer highlighter;
private final ResolvingProjectStateHolderRegistry resolvingProjectStateHolderRegistry;
private final JavaLocalizationConstant localizationConstant;
private final JavaReconcileClient client;
private EditorWithErrors editorWithErrors;
private ResolvingProjectStateHolder resolvingProjectStateHolder;
@AssistedInject
public JavaReconcilerStrategy(@Assisted @NotNull final TextEditor editor,
@Assisted final JavaCodeAssistProcessor codeAssistProcessor,
@Assisted final AnnotationModel annotationModel,
final JavaReconcileClient client,
final SemanticHighlightRenderer highlighter,
final ResolvingProjectStateHolderRegistry resolvingProjectStateHolderRegistry,
final JavaLocalizationConstant localizationConstant) {
this.editor = editor;
this.client = client;
this.codeAssistProcessor = codeAssistProcessor;
this.annotationModel = annotationModel;
this.highlighter = highlighter;
this.resolvingProjectStateHolderRegistry = resolvingProjectStateHolderRegistry;
this.localizationConstant = localizationConstant;
if (editor instanceof EditorWithErrors) {
this.editorWithErrors = ((EditorWithErrors)editor);
}
}
@Override
public void setDocument(final Document document) {
highlighter.init(editor.getEditorWidget(), document);
if (getFile() instanceof Resource) {
final Optional<Project> project = ((Resource)getFile()).getRelatedProject();
if (!project.isPresent()) {
return;
}
String projectType = project.get().getType();
resolvingProjectStateHolder = resolvingProjectStateHolderRegistry.getResolvingProjectStateHolder(projectType);
if (resolvingProjectStateHolder == null) {
return;
}
resolvingProjectStateHolder.addResolvingProjectStateListener(this);
if (resolvingProjectStateHolder.getState() == IN_PROGRESS) {
disableReconciler(localizationConstant.codeAssistErrorMessageResolvingProject());
}
}
}
@Override
public void reconcile(final DirtyRegion dirtyRegion, final Region subRegion) {
parse();
}
void parse() {
if (getFile() instanceof Resource) {
final Optional<Project> project = ((Resource)getFile()).getRelatedProject();
if (!project.isPresent()) {
return;
}
try {
client.reconcile(project.get().getLocation().toString(), JavaUtil.resolveFQN(getFile()),
new JavaReconcileClient.ReconcileCallback() {
@Override
public void onReconcile(ReconcileResult result) {
if (resolvingProjectStateHolder != null && resolvingProjectStateHolder.getState() == IN_PROGRESS) {
disableReconciler(localizationConstant.codeAssistErrorMessageResolvingProject());
return;
} else {
codeAssistProcessor.enableCodeAssistant();
}
if (result == null) {
return;
}
doReconcile(result.getProblems());
highlighter.reconcile(result.getHighlightedPositions());
}
});
} catch (RuntimeException e) {
Log.info(getClass(), e.getMessage());
}
}
}
@Override
public void reconcile(final Region partition) {
parse();
}
public VirtualFile getFile() {
return editor.getEditorInput().getFile();
}
private void doReconcile(final List<Problem> problems) {
if (this.annotationModel == null) {
return;
}
ProblemRequester problemRequester;
if (this.annotationModel instanceof ProblemRequester) {
problemRequester = (ProblemRequester)this.annotationModel;
problemRequester.beginReporting();
} else {
if (editorWithErrors != null) {
editorWithErrors.setErrorState(EditorWithErrors.EditorState.NONE);
}
return;
}
try {
boolean error = false;
boolean warning = false;
for (Problem problem : problems) {
if (!error) {
error = problem.isError();
}
if (!warning) {
warning = problem.isWarning();
}
problemRequester.acceptProblem(problem);
}
if(editorWithErrors != null) {
if (error) {
editorWithErrors.setErrorState(EditorWithErrors.EditorState.ERROR);
} else if (warning) {
editorWithErrors.setErrorState(EditorWithErrors.EditorState.WARNING);
} else {
editorWithErrors.setErrorState(EditorWithErrors.EditorState.NONE);
}
}
} catch (final Exception e) {
Log.error(getClass(), e);
} finally {
problemRequester.endReporting();
}
}
private void disableReconciler(String errorMessage) {
codeAssistProcessor.disableCodeAssistant(errorMessage);
doReconcile(Collections.<Problem>emptyList());
highlighter.reconcile(Collections.<HighlightedPosition>emptyList());
}
@Override
public void closeReconciler() {
if (resolvingProjectStateHolder != null) {
resolvingProjectStateHolder.removeResolvingProjectStateListener(this);
}
}
@Override
public void onResolvingProjectStateChanged(ResolvingProjectState state) {
switch (state) {
case IN_PROGRESS:
disableReconciler(localizationConstant.codeAssistErrorMessageResolvingProject());
break;
case RESOLVED:
parse();
break;
default:
break;
}
}
}