[PT-#150740880] File listener and project listeners mechanics

Refactor project finder into project manager

Update annotation index based on project changes

Missing comments
This commit is contained in:
BoykoAlex
2017-10-10 12:15:55 -04:00
parent 825db31d88
commit 423c6bcaef
40 changed files with 1177 additions and 359 deletions

View File

@@ -0,0 +1,109 @@
/*******************************************************************************
* Copyright (c) 2017 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.languageserver.java;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.FileObserver;
import org.springframework.ide.vscode.commons.util.FileObserver.FileListener;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.util.ListenerList;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.StringUtil;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
/**
* Base implementation of {@link JavaProjectManager}
*
* @author Alex Boyko
*
*/
public abstract class AbstractJavaProjectManager implements JavaProjectManager {
private ListenerList<Listener> listeners;
private FileObserver fileObserver;
private Supplier<FileListener> fileListener;
public AbstractJavaProjectManager() {
this.fileListener = Suppliers.memoize(() -> createFileListener());
this.listeners = new ListenerList<>();
}
protected FileListener createFileListener() {
return null;
}
@Override
public IJavaProject find(IDocument doc) {
try {
String uriStr = doc.getUri();
if (StringUtil.hasText(uriStr)) {
URI uri = new URI(uriStr);
// TODO: This only work with File uri. Should it work with others
// too?
if (uri.getScheme().equalsIgnoreCase("file")) {
File file = new File(uri).getAbsoluteFile();
return find(file);
}
}
}
catch (URISyntaxException e) {
Log.log(e);
}
return null;
}
@Override
public void setFileObserver(FileObserver fileObserver) {
FileListener listener= fileListener.get();
if (this.fileObserver != null && listener != null) {
this.fileObserver.removeListener(listener);
}
this.fileObserver = fileObserver;
if (this.fileObserver != null && listener != null) {
this.fileObserver.addListener(listener);
}
}
final protected FileObserver getFileObserver() {
return this.fileObserver;
}
@Override
public void addListener(Listener listener) {
listeners.add(listener);
}
@Override
public void removeListener(Listener listener) {
listeners.remove(listener);
}
final protected void notifyProjectCreated(IJavaProject project) {
listeners.forEach(l -> l.created(project));
}
final protected void notifyProjectChanged(IJavaProject project) {
listeners.forEach(l -> l.changed(project));
}
final protected void notifyProjectDeleted(IJavaProject project) {
listeners.forEach(l -> l.deleted(project));
}
}

View File

@@ -1,32 +1,40 @@
/*******************************************************************************
* Copyright (c) 2016, 2017 Pivotal, Inc.
* Copyright (c) 2017 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.languageserver.java;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.FileObserver;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.text.IDocument;
public class DefaultJavaProjectFinder implements JavaProjectFinder {
private final IJavaProjectFinderStrategy[] strategies;
/**
* Composite project manager that acts a single project manager but consissts of many project managers
*
* @author Alex Boyko
*
*/
public class CompositeJavaProjectManager implements JavaProjectManager {
public DefaultJavaProjectFinder(IJavaProjectFinderStrategy[] strategies) {
this.strategies = strategies;
private final JavaProjectManager[] projectManagers;
public CompositeJavaProjectManager(JavaProjectManager[] projectManagers) {
this.projectManagers = projectManagers;
}
@Override
public IJavaProject find(IDocument doc) {
try {
@@ -46,10 +54,10 @@ public class DefaultJavaProjectFinder implements JavaProjectFinder {
}
return null;
}
@Override
public IJavaProject find(File file) {
for (IJavaProjectFinderStrategy strategy : strategies) {
for (JavaProjectManager strategy : projectManagers) {
try {
IJavaProject project = strategy.find(file);
if (project != null) {
@@ -64,7 +72,7 @@ public class DefaultJavaProjectFinder implements JavaProjectFinder {
@Override
public boolean isProjectRoot(File file) {
for (IJavaProjectFinderStrategy strategy : strategies) {
for (JavaProjectManager strategy : projectManagers) {
try {
if (strategy.isProjectRoot(file)) {
return true;
@@ -75,5 +83,19 @@ public class DefaultJavaProjectFinder implements JavaProjectFinder {
}
return false;
}
public void setFileObserver(FileObserver fileObserver) {
Arrays.stream(projectManagers).forEach(pm -> pm.setFileObserver(fileObserver));
}
@Override
public void addListener(Listener listener) {
Arrays.stream(projectManagers).forEach(pm -> pm.addListener(listener));
}
@Override
public void removeListener(Listener listener) {
Arrays.stream(projectManagers).forEach(pm -> pm.removeListener(listener));
}
}

View File

@@ -1,27 +0,0 @@
/*******************************************************************************
* Copyright (c) 2016, 2017 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.languageserver.java;
import java.io.File;
import org.springframework.ide.vscode.commons.java.IJavaProject;
/**
* Strategy foe finding Java project for a document
*
* @author Alex Boyko
*/
public interface IJavaProjectFinderStrategy {
IJavaProject find(File file) throws Exception;
boolean isProjectRoot(File file);
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016-2017 Pivotal, Inc.
* Copyright (c) 2016, 2017 Pivotal, Inc.
* 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
@@ -13,12 +13,29 @@ package org.springframework.ide.vscode.commons.languageserver.java;
import java.io.File;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.FileObserver;
import org.springframework.ide.vscode.commons.util.text.IDocument;
public interface JavaProjectFinder {
/**
* Java project manager. Able to find a java project for a file or document and
* provide project change listening mechanism
*
* @author Alex Boyko
*/
public interface JavaProjectManager {
interface Listener {
void created(IJavaProject project);
void changed(IJavaProject project);
void deleted(IJavaProject project);
}
void setFileObserver(FileObserver fileObserver);
IJavaProject find(IDocument doc);
IJavaProject find(File file);
boolean isProjectRoot(File file);
void addListener(Listener listener);
void removeListener( Listener listener);
}

View File

@@ -0,0 +1,181 @@
/*******************************************************************************
* Copyright (c) 2017 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.java.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.io.File;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ExecutionException;
import org.junit.Test;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.AbstractJavaProjectManager;
import org.springframework.ide.vscode.commons.languageserver.java.CompositeJavaProjectManager;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectManager;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectManager.Listener;
import org.springframework.ide.vscode.commons.util.BasicFileObserver;
import org.springframework.ide.vscode.commons.util.FileObserver.FileListener;
import org.springframework.ide.vscode.commons.util.FileUtils;
import org.springframework.ide.vscode.commons.util.Log;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
/**
* Tests for {@link CompositeJavaProjectManager}
*
* @author Alex Boyko
*
*/
public class CompositeJavaProjectManagerTest {
private AbstractJavaProjectManager createProjectManagerForFile(String fileName) {
return new AbstractJavaProjectManager() {
private Cache<File, IJavaProject> cache = CacheBuilder.newBuilder().build();
@Override
public boolean isProjectRoot(File file) {
return FileUtils.findFile(file, fileName, false) != null;
}
@Override
public IJavaProject find(File file) {
if (fileName.equals(file.toPath().getFileName().toString())) {
try {
return cache.get(file, () -> {
return new IJavaProject() {
@Override
public IClasspath getClasspath() {
return null;
}
};
});
} catch (ExecutionException e) {
Log.log(e);
return null;
}
}
return null;
}
@Override
protected FileListener createFileListener() {
return new FileListener() {
private File getFileFromUri(String uri) {
return Paths.get(URI.create(uri)).toFile();
}
@Override
public void deleted(String uri) {
File file = getFileFromUri(uri);
IJavaProject project = cache.getIfPresent(file);
if (project != null) {
cache.invalidate(file);
notifyProjectDeleted(project);
}
}
@Override
public void created(String uri) {
}
@Override
public void changed(String uri) {
File file = getFileFromUri(uri);
IJavaProject project = cache.getIfPresent(file);
if (project != null) {
notifyProjectChanged(project);
}
}
@Override
public boolean accept(String uri) {
return fileName.equals(Paths.get(URI.create(uri)).getFileName().toString());
}
};
}
};
}
@Test
public void testListeners() throws Exception {
AbstractJavaProjectManager manager1 = createProjectManagerForFile("test-1");
AbstractJavaProjectManager manager2 = createProjectManagerForFile("test-2");
CompositeJavaProjectManager compositeManager = new CompositeJavaProjectManager(new JavaProjectManager[] {
manager1,
manager2
});
BasicFileObserver fileObserver = new BasicFileObserver();
compositeManager.setFileObserver(fileObserver);
Path containerPath = Paths.get(CompositeJavaProjectManagerTest.class.getResource("/").toURI());
File projectFile1 = containerPath.resolve("test-1").toFile();
IJavaProject p1 = compositeManager.find(projectFile1);
assertNotNull(p1);
File projectFile2 = containerPath.resolve("test-2").toFile();
IJavaProject p2 = compositeManager.find(projectFile2);
assertNotNull(p2);
IJavaProject[] projectChanged = new IJavaProject[] { null };
IJavaProject[] projectDeleted = new IJavaProject[] { null };
compositeManager.addListener(new Listener() {
@Override
public void created(IJavaProject project) {
}
@Override
public void changed(IJavaProject project) {
projectChanged[0] = project;
}
@Override
public void deleted(IJavaProject project) {
projectDeleted[0] = project;
}
});
fileObserver.notifyFileChanged(projectFile1.toURI().toString());
assertEquals(p1, projectChanged[0]);
assertNull(projectDeleted[0]);
projectChanged[0] = projectDeleted[0] = null;
fileObserver.notifyFileDeleted(projectFile1.toURI().toString());
assertNull(projectChanged[0]);
assertEquals(p1, projectDeleted[0]);
projectChanged[0] = projectDeleted[0] = null;
fileObserver.notifyFileChanged(projectFile2.toURI().toString());
assertEquals(p2, projectChanged[0]);
assertNull(projectDeleted[0]);
projectChanged[0] = projectDeleted[0] = null;
fileObserver.notifyFileDeleted(projectFile2.toURI().toString());
assertNull(projectChanged[0]);
assertEquals(p2, projectDeleted[0]);
projectChanged[0] = projectDeleted[0] = null;
}
}