diff --git a/.gitignore b/.gitignore index cb58cf4c8..0932b9cd4 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ hs_err_pid* target/ +bin/ *.log # Mac OSX aux files diff --git a/concourse/pipeline.yml b/concourse/pipeline.yml index 59756d40b..6777872e7 100644 --- a/concourse/pipeline.yml +++ b/concourse/pipeline.yml @@ -39,6 +39,14 @@ resources: secret_access_key: {{s3_secretkey}} region_name: {{s3_region}} regexp: sts4/vscode-extensions/snapshots/vscode-boot-properties-(.*).vsix +- name: s3-boot-java-vsix-snapshot + type: s3 + source: + bucket: {{s3_bucket}} + access_key_id: {{s3_accesskey}} + secret_access_key: {{s3_secretkey}} + region_name: {{s3_region}} + regexp: sts4/vscode-extensions/snapshots/vscode-boot-java-(.*).vsix - name: s3-concourse-vsix-snapshot type: s3 source: @@ -103,6 +111,10 @@ jobs: params: file: vsix-files/vscode-boot-properties-*.vsix acl: public-read + - put: s3-boot-java-vsix-snapshot + params: + file: vsix-files/vscode-boot-java-*.vsix + acl: public-read - put: s3-concourse-vsix-snapshot params: file: vsix-files/vscode-concourse-*.vsix @@ -144,6 +156,10 @@ jobs: passed: - build-vsix-snapshots trigger: true + - get: s3-boot-java-vsix-snapshot + passed: + - build-vsix-snapshots + trigger: true - get: s3-concourse-vsix-snapshot passed: - build-vsix-snapshots diff --git a/concourse/tasks/build-website.sh b/concourse/tasks/build-website.sh index 997920bce..adfa01748 100755 --- a/concourse/tasks/build-website.sh +++ b/concourse/tasks/build-website.sh @@ -15,6 +15,8 @@ export vscode_manifest_yaml=$(basename s3-manifest-yaml-vsix-${dist_type}/*.vsix echo "vscode_manifest_yaml=$vscode_manifest_yaml" export vscode_boot_properties=$(basename s3-boot-properties-vsix-${dist_type}/*.vsix) echo "vscode_boot_properties=$vscode_boot_properties" +export vscode_boot_java=$(basename s3-boot-java-vsix-${dist_type}/*.vsix) +echo "vscode_boot_java=$vscode_boot_java" export vscode_concourse=$(basename s3-concourse-vsix-${dist_type}/*.vsix) echo "vscode_concourse=$vscode_concourse" @@ -23,6 +25,9 @@ envsubst > "$target/vscode-extensions-snippet.html" << XXXXXX
  • Spring Boot Property Language Server: ${vscode_boot_properties}
  • +
  • Spring Boot Java Language Server: + ${vscode_boot_java} +
  • Cloud Foundry Manifest Language Server: ${vscode_manifest_yaml}
  • diff --git a/concourse/tasks/build-website.yml b/concourse/tasks/build-website.yml index e10e27b36..ac4840efd 100644 --- a/concourse/tasks/build-website.yml +++ b/concourse/tasks/build-website.yml @@ -2,6 +2,7 @@ inputs: - name: sts4 - name: s3-manifest-yaml-vsix-snapshot - name: s3-boot-properties-vsix-snapshot +- name: s3-boot-java-vsix-snapshot - name: s3-concourse-vsix-snapshot outputs: - name: website diff --git a/eclipse-distribution/org.springframework.boot.ide.product.e47/category.xml b/eclipse-distribution/org.springframework.boot.ide.product.e47/category.xml index 6b92a63b4..7c3f559ae 100644 --- a/eclipse-distribution/org.springframework.boot.ide.product.e47/category.xml +++ b/eclipse-distribution/org.springframework.boot.ide.product.e47/category.xml @@ -55,4 +55,9 @@ + + + + diff --git a/eclipse-distribution/org.springframework.boot.ide.product.e47/org.springframework.boot.ide.product b/eclipse-distribution/org.springframework.boot.ide.product.e47/org.springframework.boot.ide.product index 55a168fbe..7b6a82a93 100644 --- a/eclipse-distribution/org.springframework.boot.ide.product.e47/org.springframework.boot.ide.product +++ b/eclipse-distribution/org.springframework.boot.ide.product.e47/org.springframework.boot.ide.product @@ -83,6 +83,7 @@ openFile + diff --git a/eclipse-distribution/org.springframework.boot.ide.repository.e47/category.xml b/eclipse-distribution/org.springframework.boot.ide.repository.e47/category.xml index 6b92a63b4..7c3f559ae 100644 --- a/eclipse-distribution/org.springframework.boot.ide.repository.e47/category.xml +++ b/eclipse-distribution/org.springframework.boot.ide.repository.e47/category.xml @@ -55,4 +55,9 @@ + + + + diff --git a/eclipse-language-servers/org.springframework.boot.ide.cloudfoundry.server/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.boot.ide.cloudfoundry.server/META-INF/MANIFEST.MF index f27450134..89b9d13c4 100644 --- a/eclipse-language-servers/org.springframework.boot.ide.cloudfoundry.server/META-INF/MANIFEST.MF +++ b/eclipse-language-servers/org.springframework.boot.ide.cloudfoundry.server/META-INF/MANIFEST.MF @@ -10,8 +10,8 @@ Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0", org.eclipse.ui.genericeditor;bundle-version="1.0.0", org.eclipse.jface.text;bundle-version="3.11.100", org.eclipse.jdt.ui;bundle-version="3.13.0", - org.eclipse.tm4e.core;bundle-version="1.0.0", - org.eclipse.tm4e.ui;bundle-version="1.0.0" + org.eclipse.tm4e.core;bundle-version="0.1.0", + org.eclipse.tm4e.ui;bundle-version="0.1.0" Import-Package: org.eclipse.jface.preference, org.eclipse.lsp4j.jsonrpc.messages;version="0.1.0.v20170117-0759", org.eclipse.lsp4j.services;version="0.1.0.v20170117-0759", diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers.feature/build.properties b/eclipse-language-servers/org.springframework.boot.ide.java.servers.feature/build.properties new file mode 100644 index 000000000..64f93a9f0 --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers.feature/feature.xml b/eclipse-language-servers/org.springframework.boot.ide.java.servers.feature/feature.xml new file mode 100644 index 000000000..310128412 --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers.feature/feature.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers.feature/pom.xml b/eclipse-language-servers/org.springframework.boot.ide.java.servers.feature/pom.xml new file mode 100644 index 000000000..e8c8474ff --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers.feature/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + org.springframework.boot.ide + org.springframework.boot.ide.servers + 4.0.0-SNAPSHOT + ../pom.xml + + + org.springframework.boot.ide.java.servers.feature + eclipse-feature + + diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers/.classpath b/eclipse-language-servers/org.springframework.boot.ide.java.servers/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers/.project b/eclipse-language-servers/org.springframework.boot.ide.java.servers/.project new file mode 100644 index 000000000..1dac181c4 --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers/.project @@ -0,0 +1,28 @@ + + + org.springframework.boot.ide.java.servers + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers/.settings/org.eclipse.jdt.core.prefs b/eclipse-language-servers/org.springframework.boot.ide.java.servers/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.boot.ide.java.servers/META-INF/MANIFEST.MF new file mode 100644 index 000000000..e93d746a6 --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers/META-INF/MANIFEST.MF @@ -0,0 +1,21 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Servers +Bundle-SymbolicName: org.springframework.boot.ide.java.servers;singleton:=true +Bundle-Version: 4.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0", + org.eclipse.core.runtime;bundle-version="3.12.0", + org.eclipse.lsp4e;bundle-version="0.1.0", + org.eclipse.ui.genericeditor;bundle-version="1.0.0", + org.eclipse.jface.text;bundle-version="3.11.100", + org.eclipse.jdt.ui;bundle-version="3.13.0", + org.eclipse.lsp4j, + org.eclipse.ui.workbench, + org.eclipse.jface, + org.eclipse.xtext.xbase.lib +Import-Package: com.google.gson;version="2.7.0", + org.eclipse.jface.preference, + org.eclipse.lsp4j.jsonrpc.messages;version="0.1.0.v20170117-0759", + org.eclipse.lsp4j.services;version="0.1.0.v20170117-0759", + org.osgi.framework diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers/build.properties b/eclipse-language-servers/org.springframework.boot.ide.java.servers/build.properties new file mode 100644 index 000000000..3b7db0f69 --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + servers/ diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers/plugin.xml b/eclipse-language-servers/org.springframework.boot.ide.java.servers/plugin.xml new file mode 100644 index 000000000..4066c2d39 --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers/plugin.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers/pom.xml b/eclipse-language-servers/org.springframework.boot.ide.java.servers/pom.xml new file mode 100644 index 000000000..1308d7ebd --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + + org.springframework.boot.ide + org.springframework.boot.ide.servers + 4.0.0-SNAPSHOT + ../pom.xml + + + org.springframework.boot.ide.java.servers + eclipse-plugin + + + + org.springframework.ide.vscode + vscode-boot-java + 0.0.1-SNAPSHOT + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + copy + prepare-package + + copy + + + + + org.springframework.ide.vscode + vscode-boot-java + true + ${project.build.directory}/../servers + + + true + true + + + + + + + + diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/Constants.java b/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/Constants.java new file mode 100644 index 000000000..622375721 --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/Constants.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * 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.boot.ide.java.servers; + +/** + * @author Martin Lippert + */ +public class Constants { + + public static final String PLUGIN_ID = "org.springframework.boot.ide.java.servers"; + +} diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/SpringBootJavaCompletionProposalComputer.java b/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/SpringBootJavaCompletionProposalComputer.java new file mode 100644 index 000000000..fd1b72ae7 --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/SpringBootJavaCompletionProposalComputer.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * 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.boot.ide.java.servers; + +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.ui.text.java.ContentAssistInvocationContext; +import org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.lsp4e.operations.completion.LSContentAssistProcessor; + +/** + * @author Martin Lippert + */ +@SuppressWarnings("restriction") +public class SpringBootJavaCompletionProposalComputer implements IJavaCompletionProposalComputer { + + private LSContentAssistProcessor lsContentAssistProcessor; + + public SpringBootJavaCompletionProposalComputer() { + lsContentAssistProcessor = new LSContentAssistProcessor(); + } + + @Override + public void sessionStarted() { + } + + @Override + public List computeCompletionProposals(ContentAssistInvocationContext context, + IProgressMonitor monitor) { + System.out.println("Spring Boot Java Completion Proposal - compute completion proposals"); + + ICompletionProposal[] proposals = lsContentAssistProcessor.computeCompletionProposals(context.getViewer(), context.getInvocationOffset()); + return Arrays.asList(proposals); + } + + @Override + public List computeContextInformation(ContentAssistInvocationContext context, + IProgressMonitor monitor) { + IContextInformation[] contextInformation = lsContentAssistProcessor.computeContextInformation(context.getViewer(), context.getInvocationOffset()); + return Arrays.asList(contextInformation); + } + + @Override + public String getErrorMessage() { + return lsContentAssistProcessor.getErrorMessage(); + } + + @Override + public void sessionEnded() { + } + +} diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/SpringBootJavaHoverProvider.java b/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/SpringBootJavaHoverProvider.java new file mode 100644 index 000000000..eabc1d7b0 --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/SpringBootJavaHoverProvider.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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.boot.ide.java.servers; + +import org.eclipse.jdt.ui.text.java.hover.IJavaEditorTextHover; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.lsp4e.operations.hover.LSBasedHover; +import org.eclipse.ui.IEditorPart; + +/** + * @author Martin Lippert + */ +@SuppressWarnings("restriction") +public class SpringBootJavaHoverProvider implements IJavaEditorTextHover { + + private LSBasedHover lsBasedHover; + + public SpringBootJavaHoverProvider() { + lsBasedHover = new LSBasedHover(); + } + + @Override + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + return this.lsBasedHover.getHoverInfo(textViewer, hoverRegion); + } + + @Override + public IRegion getHoverRegion(ITextViewer textViewer, int offset) { + return this.lsBasedHover.getHoverRegion(textViewer, offset); + } + + @Override + public void setEditor(IEditorPart editor) { + } + +} diff --git a/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/SpringBootJavaLanguageServer.java b/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/SpringBootJavaLanguageServer.java new file mode 100644 index 000000000..4369f3e62 --- /dev/null +++ b/eclipse-language-servers/org.springframework.boot.ide.java.servers/src/org/springframework/boot/ide/java/servers/SpringBootJavaLanguageServer.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * 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.boot.ide.java.servers; + +import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jdt.internal.launching.StandardVMType; +import org.eclipse.jdt.launching.IVMInstall; +import org.eclipse.jdt.launching.JavaRuntime; +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.lsp4e.server.ProcessStreamConnectionProvider; +import org.eclipse.lsp4j.jsonrpc.messages.Message; +import org.eclipse.lsp4j.jsonrpc.messages.NotificationMessage; +import org.eclipse.lsp4j.services.LanguageServer; +import org.eclipse.ui.PlatformUI; +import org.osgi.framework.Bundle; + +import com.google.gson.JsonObject; + +/** + * @author Martin Lippert + */ +@SuppressWarnings("restriction") +public class SpringBootJavaLanguageServer extends ProcessStreamConnectionProvider { + + public SpringBootJavaLanguageServer() { + List commands = new ArrayList<>(); + commands.add(getJDKLocation()); + + commands.add("-Xdebug"); + commands.add("-Xrunjdwp:server=y,transport=dt_socket,address=4000,suspend=n"); + + commands.add("-jar"); + commands.add(getLanguageServerJARLocation()); + + String workingDir = getWorkingDirLocation(); + + setCommands(commands); + setWorkingDirectory(workingDir); + } + + public void handleMessage(Message message, LanguageServer languageServer, String rootPath) { + if (message instanceof NotificationMessage) { + NotificationMessage notificationMessage = (NotificationMessage) message; + if ("sts/progress".equals(notificationMessage.getMethod())) { + JsonObject params = (JsonObject) notificationMessage.getParams(); + String status = params.has("statusMsg") ? params.get("statusMsg").getAsString() : ""; + showStatusMessage(status); + } + } + } + + private void showStatusMessage(final String status) { + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + IStatusLineManager statusLineManager = getStatusLineManager(); + if (statusLineManager != null) { + statusLineManager.setMessage(status); + } + } + }); + } + + private IStatusLineManager getStatusLineManager() { + try { + return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor().getEditorSite().getActionBars().getStatusLineManager(); + } + catch (NullPointerException e) { + return null; + } + } + + protected String getJDKLocation() { + IVMInstall jdk = JavaRuntime.getDefaultVMInstall(); + File javaExecutable = StandardVMType.findJavaExecutable(jdk.getInstallLocation()); + return javaExecutable.getAbsolutePath(); + } + + protected String getLanguageServerJARLocation() { + String languageServer = "vscode-boot-java-0.0.1-SNAPSHOT.jar"; + + Bundle bundle = Platform.getBundle(Constants.PLUGIN_ID); + File dataFile = bundle.getDataFile(languageServer); +// if (!dataFile.exists()) { + try { + copyLanguageServerJAR(languageServer); + } + catch (Exception e) { + e.printStackTrace(); + } +// } + + return dataFile.getAbsolutePath(); + } + + protected String getWorkingDirLocation() { + // TODO: identify a reasonable working directory for the language server process + return System.getProperty("user.dir"); + } + + protected void copyLanguageServerJAR(String languageServerJarName) throws Exception { + Bundle bundle = Platform.getBundle(Constants.PLUGIN_ID); + InputStream stream = FileLocator.openStream( bundle, new Path("servers/" + languageServerJarName), false ); + + File dataFile = bundle.getDataFile(languageServerJarName); + Files.copy(stream, dataFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + +} diff --git a/eclipse-language-servers/org.springframework.boot.ide.properties.servers/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.boot.ide.properties.servers/META-INF/MANIFEST.MF index c4e708121..ee2ce9ef6 100644 --- a/eclipse-language-servers/org.springframework.boot.ide.properties.servers/META-INF/MANIFEST.MF +++ b/eclipse-language-servers/org.springframework.boot.ide.properties.servers/META-INF/MANIFEST.MF @@ -10,8 +10,8 @@ Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0", org.eclipse.ui.genericeditor;bundle-version="1.0.0", org.eclipse.jface.text;bundle-version="3.11.100", org.eclipse.jdt.ui;bundle-version="3.13.0", - org.eclipse.tm4e.core;bundle-version="1.0.0", - org.eclipse.tm4e.ui;bundle-version="1.0.0", + org.eclipse.tm4e.core;bundle-version="0.1.0", + org.eclipse.tm4e.ui;bundle-version="0.1.0", org.eclipse.lsp4j, org.eclipse.ui.workbench, org.eclipse.jface diff --git a/eclipse-language-servers/org.springframework.boot.ide.properties.servers/src/org/springframework/boot/ide/properties/servers/SpringBootPropertiesLanguageServer.java b/eclipse-language-servers/org.springframework.boot.ide.properties.servers/src/org/springframework/boot/ide/properties/servers/SpringBootPropertiesLanguageServer.java index c160c5c8c..3d68a38e5 100644 --- a/eclipse-language-servers/org.springframework.boot.ide.properties.servers/src/org/springframework/boot/ide/properties/servers/SpringBootPropertiesLanguageServer.java +++ b/eclipse-language-servers/org.springframework.boot.ide.properties.servers/src/org/springframework/boot/ide/properties/servers/SpringBootPropertiesLanguageServer.java @@ -94,14 +94,14 @@ public class SpringBootPropertiesLanguageServer extends ProcessStreamConnectionP Bundle bundle = Platform.getBundle(Constants.PLUGIN_ID); File dataFile = bundle.getDataFile(languageServer); - if (!dataFile.exists()) { +// if (!dataFile.exists()) { try { copyLanguageServerJAR(languageServer); } catch (Exception e) { e.printStackTrace(); } - } +// } return dataFile.getAbsolutePath(); } diff --git a/eclipse-language-servers/org.springframework.boot.ide.servers.repository/category.xml b/eclipse-language-servers/org.springframework.boot.ide.servers.repository/category.xml index d11905dad..0f9aacb75 100644 --- a/eclipse-language-servers/org.springframework.boot.ide.servers.repository/category.xml +++ b/eclipse-language-servers/org.springframework.boot.ide.servers.repository/category.xml @@ -10,6 +10,10 @@ + + + + diff --git a/eclipse-language-servers/pom.xml b/eclipse-language-servers/pom.xml index bd1f778a1..ab0e7382c 100644 --- a/eclipse-language-servers/pom.xml +++ b/eclipse-language-servers/pom.xml @@ -30,6 +30,9 @@ org.springframework.boot.ide.properties.servers org.springframework.boot.ide.properties.servers.feature + org.springframework.boot.ide.java.servers + org.springframework.boot.ide.java.servers.feature + org.springframework.boot.ide.cloudfoundry.server org.springframework.boot.ide.cloudfoundry.server.feature @@ -81,6 +84,11 @@ p2 http://download.eclipse.org/tools/orbit/downloads/drops/S20161205183421/repository/ + + lsp4j-snapshots + p2 + http://services.typefox.io/open-source/jenkins/job/lsp4j/job/master/lastStableBuild/artifact/build/p2-repository/ + lsp4e p2 @@ -89,7 +97,7 @@ tm4e p2 - http://oss.opensagres.fr/textmate/1.0.0-SNAPSHOT/ + http://oss.opensagres.fr/textmate/0.1.0-SNAPSHOT/ diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFDomain.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFDomain.java new file mode 100644 index 000000000..e231abde7 --- /dev/null +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFDomain.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * 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.cloudfoundry.client; + +public interface CFDomain { + + String getName(); + +} diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFDomainImpl.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFDomainImpl.java new file mode 100644 index 000000000..a8e7be670 --- /dev/null +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFDomainImpl.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.cloudfoundry.client; + +class CFDomainImpl implements CFDomain { + + private final String name; + + public CFDomainImpl(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CFDomainImpl other = (CFDomainImpl) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + +} diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFEntities.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFEntities.java index 9973cfdc3..395548f86 100644 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFEntities.java +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFEntities.java @@ -29,4 +29,7 @@ public class CFEntities { /* dasboard Url */ null); } + public static CFDomain createDomain(String name) { + return new CFDomainImpl(name); + } } diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/ClientRequests.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/ClientRequests.java index 407b85533..74e797579 100644 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/ClientRequests.java +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/ClientRequests.java @@ -17,4 +17,6 @@ public interface ClientRequests { List getBuildpacks() throws Exception; List getServices() throws Exception; + List getDomains() throws Exception; + } diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTarget.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTarget.java index 4c6ba97c1..f2087ddf4 100644 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTarget.java +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/cftarget/CFTarget.java @@ -15,6 +15,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFBuildpack; +import org.springframework.ide.vscode.commons.cloudfoundry.client.CFDomain; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFServiceInstance; import org.springframework.ide.vscode.commons.cloudfoundry.client.ClientRequests; @@ -37,15 +38,21 @@ public class CFTarget { /* * Cached information */ - private final LoadingCache> buildpacksCache; - private final LoadingCache> servicesCache; + private LoadingCache> buildpacksCache; + private LoadingCache> servicesCache; + private LoadingCache> domainCache; private CFCallableContext callableContext; - public CFTarget(String targetName, CFClientParams params, ClientRequests requests, CFCallableContext callableContext) { + public CFTarget(String targetName, CFClientParams params, ClientRequests requests, + CFCallableContext callableContext) { this.params = params; this.requests = requests; this.targetName = targetName; this.callableContext = callableContext; + initCache(requests); + } + + private void initCache(ClientRequests requests) { CacheLoader> servicesLoader = new CacheLoader>() { @Override @@ -71,12 +78,23 @@ public class CFTarget { }; this.buildpacksCache = CacheBuilder.newBuilder() .expireAfterAccess(CFTargetCache.TARGET_EXPIRATION, TimeUnit.HOURS).build(buildpacksLoader); + + CacheLoader> domainLoader = new CacheLoader>() { + + @Override + public List load(String key) throws Exception { + return runAndCheckForFailure(() -> requests.getDomains()); + } + + }; + this.domainCache = CacheBuilder.newBuilder() + .expireAfterAccess(CFTargetCache.TARGET_EXPIRATION, TimeUnit.HOURS).build(domainLoader); } - + protected T runAndCheckForFailure(Callable callable) throws Exception { return callableContext.checkConnection(callable); } - + public boolean hasConnectionError() { return callableContext.hasConnectionError(); } @@ -102,6 +120,11 @@ public class CFTarget { String key = getName(); return this.servicesCache.get(key); } + + public List getDomains() throws Exception { + String key = getName(); + return this.domainCache.get(key); + } public ClientRequests getClientRequests() { return requests; diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CFWrappingV2.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CFWrappingV2.java index a3b38fd70..b16829bb4 100644 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CFWrappingV2.java +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/CFWrappingV2.java @@ -11,10 +11,11 @@ package org.springframework.ide.vscode.commons.cloudfoundry.client.v2; import org.cloudfoundry.operations.buildpacks.Buildpack; -import org.cloudfoundry.operations.services.ServiceInstance; +import org.cloudfoundry.operations.domains.Domain; import org.cloudfoundry.operations.services.ServiceInstanceSummary; import org.cloudfoundry.operations.services.ServiceInstanceType; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFBuildpack; +import org.springframework.ide.vscode.commons.cloudfoundry.client.CFDomain; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFEntities; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFServiceInstance; @@ -32,6 +33,11 @@ public class CFWrappingV2 { return CFEntities.createBuildpack(name); } + public static CFDomain wrap(Domain domain) { + String name = domain.getName(); + return CFEntities.createDomain(name); + } + public static CFServiceInstance wrap(ServiceInstanceSummary serviceInstance) { String name = serviceInstance.getName(); String plan = serviceInstance.getPlan(); diff --git a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/DefaultClientRequestsV2.java b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/DefaultClientRequestsV2.java index 3dd656f61..30646d1d4 100644 --- a/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/DefaultClientRequestsV2.java +++ b/vscode-extensions/commons/commons-cf/src/main/java/org/springframework/ide/vscode/commons/cloudfoundry/client/v2/DefaultClientRequestsV2.java @@ -18,6 +18,7 @@ import org.cloudfoundry.client.CloudFoundryClient; import org.cloudfoundry.operations.CloudFoundryOperations; import org.cloudfoundry.operations.DefaultCloudFoundryOperations; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFBuildpack; +import org.springframework.ide.vscode.commons.cloudfoundry.client.CFDomain; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFServiceInstance; import org.springframework.ide.vscode.commons.cloudfoundry.client.ClientRequests; import org.springframework.ide.vscode.commons.cloudfoundry.client.ClientTimeouts; @@ -82,7 +83,22 @@ public class DefaultClientRequestsV2 implements ClientRequests { ) ); } + + @Override + public List getDomains() throws Exception { + return ReactorUtils.get(timeouts.getBuildpacksTimeout(), CancelationTokens.NULL, + log("operations.domains.list", + _operations + .domains() + .list() + .map(CFWrappingV2::wrap) + .collectList() + .map(ImmutableList::copyOf) + ) + ); + } + @Override public List getBuildpacks() throws Exception { return ReactorUtils.get(timeouts.getBuildpacksTimeout(), CancelationTokens.NULL, diff --git a/vscode-extensions/commons/commons-cf/src/test/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFClientTest.java b/vscode-extensions/commons/commons-cf/src/test/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFClientTest.java index 32d6a8a65..e53dddd29 100644 --- a/vscode-extensions/commons/commons-cf/src/test/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFClientTest.java +++ b/vscode-extensions/commons/commons-cf/src/test/java/org/springframework/ide/vscode/commons/cloudfoundry/client/CFClientTest.java @@ -20,6 +20,7 @@ import java.util.concurrent.Callable; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFParamsProviderMessages; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTarget; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetCache; @@ -28,6 +29,8 @@ import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.Conne import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.NoTargetsException; import org.springframework.ide.vscode.commons.util.ExceptionUtil; +import com.google.common.collect.ImmutableList; + public class CFClientTest { MockCfCli cloudfoundry = new MockCfCli(); @@ -70,6 +73,62 @@ public class CFClientTest { CFTarget target = targetCache.getOrCreate().get(0); assertError(() -> target.getBuildpacks(), ConnectionException.class, expectedMessages.noNetworkConnection()); } + + @Test + public void testUnknownHostDomains() throws Exception { + ClientRequests client = cloudfoundry.client; + when(client.getDomains()).thenThrow(new UnknownHostException("api.run.pivotal.io")); + CFTarget target = targetCache.getOrCreate().get(0); + assertError(() -> target.getDomains(), ConnectionException.class, expectedMessages.noNetworkConnection()); + } + + @Test + public void testBuildpacksFromTarget() throws Exception { + ClientRequests client = cloudfoundry.client; + CFBuildpack buildpack = Mockito.mock(CFBuildpack.class); + when(buildpack.getName()).thenReturn("java_buildpack"); + when(client.getBuildpacks()).thenReturn(ImmutableList.of(buildpack)); + + CFTarget target = targetCache.getOrCreate().get(0); + assertEquals("java_buildpack", target.getBuildpacks().get(0).getName()); + } + + @Test + public void testDomainsFromTarget() throws Exception { + ClientRequests client = cloudfoundry.client; + CFDomain domain = Mockito.mock(CFDomain.class); + when(domain.getName()).thenReturn("cfapps.io"); + when(client.getDomains()).thenReturn(ImmutableList.of(domain)); + + CFTarget target = targetCache.getOrCreate().get(0); + assertEquals("cfapps.io", target.getDomains().get(0).getName()); + } + + @Test + public void testServicesFromTarget() throws Exception { + ClientRequests client = cloudfoundry.client; + CFServiceInstance service = Mockito.mock(CFServiceInstance.class); + when(service.getName()).thenReturn("appdb"); + when(service.getPlan()).thenReturn("spark"); + when(service.getService()).thenReturn("cleardb"); + + when(client.getServices()).thenReturn(ImmutableList.of(service)); + + CFTarget target = targetCache.getOrCreate().get(0); + assertEquals("appdb", target.getServices().get(0).getName()); + assertEquals("spark", target.getServices().get(0).getPlan()); + assertEquals("cleardb", target.getServices().get(0).getService()); + } + + @Test + public void testNoServicesFromTarget() throws Exception { + ClientRequests client = cloudfoundry.client; + + when(client.getServices()).thenReturn(ImmutableList.of()); + + CFTarget target = targetCache.getOrCreate().get(0); + assertTrue(target.getServices().isEmpty()); + } protected void assertError(Callable callable, Class expected, String expectedMessage) throws Exception { diff --git a/vscode-extensions/commons/commons-gradle/.classpath b/vscode-extensions/commons/commons-gradle/.classpath new file mode 100644 index 000000000..fae1a2b37 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/.classpath @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vscode-extensions/commons/commons-gradle/.project b/vscode-extensions/commons/commons-gradle/.project new file mode 100644 index 000000000..c9d9c8fb0 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/.project @@ -0,0 +1,23 @@ + + + commons-gradle + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/vscode-extensions/commons/commons-gradle/.settings/org.eclipse.core.resources.prefs b/vscode-extensions/commons/commons-gradle/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..29abf9995 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/vscode-extensions/commons/commons-gradle/.settings/org.eclipse.jdt.core.prefs b/vscode-extensions/commons/commons-gradle/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..714351aec --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/vscode-extensions/commons/commons-gradle/.settings/org.eclipse.m2e.core.prefs b/vscode-extensions/commons/commons-gradle/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 000000000..f897a7f1c --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/vscode-extensions/commons/commons-gradle/pom.xml b/vscode-extensions/commons/commons-gradle/pom.xml new file mode 100644 index 000000000..5e9a84009 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/pom.xml @@ -0,0 +1,41 @@ + + 4.0.0 + + commons-gradle + commons-gradle + Gradle Utilities + + + org.springframework.ide.vscode + commons-parent + 0.0.1-SNAPSHOT + ../pom.xml + + + + 3.3 + + + + + gradle-repo + Gradle Tooling Repo + https://repo.gradle.org/gradle/libs-releases + + + + + + org.springframework.ide.vscode + commons-java + ${project.version} + + + org.gradle + gradle-tooling-api + ${gradle-tooling.version} + + + + \ No newline at end of file diff --git a/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleCore.java b/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleCore.java new file mode 100644 index 000000000..206148de7 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleCore.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * 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.gradle; + +import java.io.File; + +import org.gradle.tooling.GradleConnectionException; +import org.gradle.tooling.GradleConnector; +import org.gradle.tooling.ProjectConnection; +import org.gradle.tooling.model.build.BuildEnvironment; +import org.gradle.tooling.model.eclipse.EclipseProject; +import org.springframework.ide.vscode.commons.util.Assert; + +/** + * Gradle API tooling utility + * + * @author Alex Boyko + * + */ +public class GradleCore { + + @FunctionalInterface + public interface GradleConfiguration { + void configure(GradleConnector connector); + } + + public interface GradleCoreProject { + EclipseProject getProject(); + BuildEnvironment getBuildEnvironment(); + } + + static final String GRADLE_BUILD_FILE = "build.gradle"; + + private static GradleCore defaultInstance = null; + + public static GradleCore getDefault() { + if (defaultInstance == null) { + defaultInstance = new GradleCore(); + } + return defaultInstance; + } + + private GradleConfiguration configuration; + + public GradleCore() { + this.configuration = (connector) -> {}; + } + + public GradleCore(GradleConfiguration configuration) { + Assert.isNotNull(configuration); + this.configuration = configuration; + } + + public T getModel(File projectDir, Class modelType) throws GradleException { + ProjectConnection connection = null; + try { + GradleConnector gradleConnector = GradleConnector.newConnector().forProjectDirectory(projectDir); + configuration.configure(gradleConnector); + connection = gradleConnector.connect(); + return connection.getModel(modelType); + } catch (GradleConnectionException e) { + throw new GradleException(e); + } finally { + if (connection != null) { + connection.close(); + } + } + } + +} diff --git a/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleException.java b/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleException.java new file mode 100644 index 000000000..75342b9ca --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleException.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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.gradle; + +import java.util.Arrays; +import java.util.stream.Collectors; + +/** + * Gradle wrapper exception + * + * @author Alex Boyko + * + */ +public class GradleException extends Exception { + + private static final long serialVersionUID = 7958309594787399714L; + + private Throwable[] t; + + public GradleException() { + super(); + } + + public GradleException(Throwable... t) { + super(); + this.t = t; + } + + @Override + public String getMessage() { + if (t != null) { + return String.join("\n", Arrays.stream(t).map(t -> t.getMessage()).collect(Collectors.toList())); + } + return super.getMessage(); + } + +} diff --git a/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleJavaProject.java b/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleJavaProject.java new file mode 100644 index 000000000..ae7121144 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleJavaProject.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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.gradle; + +import java.io.File; + +import org.springframework.ide.vscode.commons.java.IJavaProject; + +/** + * Implementation of Gradle Java project + * + * @author Alex Boyko + * + */ +public class GradleJavaProject implements IJavaProject { + + private GradleProjectClasspath classpath; + + public GradleJavaProject(GradleCore gradle, File projectDir) throws GradleException { + this.classpath = new GradleProjectClasspath(gradle, projectDir); + } + + @Override + public GradleProjectClasspath getClasspath() { + return classpath; + } + +} diff --git a/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectClasspath.java b/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectClasspath.java new file mode 100644 index 000000000..c7b2b8379 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectClasspath.java @@ -0,0 +1,207 @@ +/******************************************************************************* + * 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.gradle; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.gradle.tooling.model.build.BuildEnvironment; +import org.gradle.tooling.model.eclipse.EclipseProject; +import org.springframework.ide.vscode.commons.jandex.JandexClasspath; +import org.springframework.ide.vscode.commons.jandex.JandexIndex; +import org.springframework.ide.vscode.commons.java.IClasspath; +import org.springframework.ide.vscode.commons.java.IJavadocProvider; +import org.springframework.ide.vscode.commons.java.parser.ParserJavadocProvider; +import org.springframework.ide.vscode.commons.javadoc.HtmlJavadocProvider; +import org.springframework.ide.vscode.commons.javadoc.SourceUrlProviderFromSourceContainer; +import org.springframework.ide.vscode.commons.util.Log; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; + +/** + * Implementation of {@link IClasspath} for Gradle projects + * + * @author Alex Boyko + * + */ +public class GradleProjectClasspath extends JandexClasspath { + + private static final String JAVA_HOME = "java.home"; + private static final String JAVA_RUNTIME_VERSION = "java.runtime.version"; + private static final String JAVA_BOOT_CLASS_PATH = "sun.boot.class.path"; + + private EclipseProject gradleProject; + private Supplier buildEnvironment; + + public GradleProjectClasspath(GradleCore gradle, File projectDir) throws GradleException { + super(); + this.gradleProject = gradle.getModel(projectDir, EclipseProject.class); + this.buildEnvironment = Suppliers.memoize(() -> { + try { + return gradle.getModel(projectDir, BuildEnvironment.class); + } catch (GradleException e) { + Log.log(e); + return null; + } + }); + } + + @Override + protected JandexIndex[] getBaseIndices() { + return new JandexIndex[] { new JandexIndex(getJreLibs().map(path -> path.toFile()).collect(Collectors.toList()), + jarFile -> findIndexFile(jarFile), (classpathResource) -> { + try { + String javaVersion = getJavaRuntimeMinorVersion(); + if (javaVersion == null) { + javaVersion = "8"; + } + URL javadocUrl = new URL("http://docs.oracle.com/javase/" + javaVersion + "/docs/api/"); + return new HtmlJavadocProvider( + (type) -> SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER + .sourceUrl(javadocUrl, type)); + } catch (MalformedURLException e) { + Log.log(e); + return null; + } + }) }; + } + + @Override + public Stream getClasspathEntries() throws Exception { + return Stream.concat(gradleProject.getClasspath().stream().map(dep -> dep.getFile().toPath()), + gradleProject.getProjectDependencies().stream().map(project -> new File(project.getPath()).toPath())); + } + + @Override + public Stream getClasspathResources() { + return gradleProject.getSourceDirectories().stream().map(sourceDirectory -> sourceDirectory.getDirectory()).flatMap(folder -> { + try { + return Files.walk(folder.toPath()) + .filter(path -> Files.isRegularFile(path)) + .map(path -> folder.toPath().relativize(path)) + .map(relativePath -> relativePath.toString()) + .filter(pathString -> !pathString.endsWith(".java") && !pathString.endsWith(".class")); + } catch (IOException e) { + return Stream.empty(); + } + }); + } + + public Path getOutputFolder() { + return gradleProject.getProjectDirectory().toPath().resolve(gradleProject.getOutputLocation().getPath()); + } + + public String getName() { + return gradleProject.getName(); + } + + public boolean exists() { + return gradleProject != null; + } + + @Override + protected IJavadocProvider createParserJavadocProvider(File classpathResource) { + if (classpathResource.isDirectory()) { + Optional classpathFolder = gradleProject.getSourceDirectories().stream() + .map(dir -> dir.getDirectory()) + .filter(dir -> classpathResource.toPath().startsWith(dir.toPath())) + .findFirst(); + if (classpathFolder.isPresent()) { + return new ParserJavadocProvider(type -> { + return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER + .sourceUrl(classpathFolder.get().toURI().toURL(), type); + }); + + } + } else { + + } + return null; + } + + @Override + protected IJavadocProvider createHtmlJavdocProvider(File classpathResource) { + return null; + } + + public String getGradleVersion() throws GradleException { + if (buildEnvironment.get() == null) { + throw new GradleException(new Exception("Cannot find Gradle version")); + } else { + return buildEnvironment.get().getGradle().getGradleVersion(); + } + } + + public File getGradleHome() throws GradleException { + if (buildEnvironment.get() == null) { + throw new GradleException(new Exception("Cannot find Gradle home folder")); + } else { + return buildEnvironment.get().getGradle().getGradleUserHome(); + } + } + + public String getJavaRuntimeVersion() { + return System.getProperty(JAVA_RUNTIME_VERSION); + } + + public String getJavaRuntimeMinorVersion() { + String fullVersion = getJavaRuntimeVersion(); + String[] tokenized = fullVersion.split("\\."); + if (tokenized.length > 1) { + return tokenized[1]; + } else { + Log.log("Cannot determine minor version for the Java Runtime Version: " + fullVersion); + return null; + } + } + + private String getJavaHome() { + if (buildEnvironment.get() == null) { + return System.getProperty(JAVA_HOME); + } else { + return buildEnvironment.get().getJava().getJavaHome().toString(); + } + } + + private Stream getJreLibs() { + String s = System.getProperty(JAVA_BOOT_CLASS_PATH); + return Arrays.stream(s.split(File.pathSeparator)) + .map(strPath -> strPath.replace(System.getProperty(JAVA_HOME), getJavaHome())) + .map(File::new) + .filter(f -> f.canRead()) + .map(f -> f.toPath()); + } + + private File findIndexFile(File jarFile) { + String suffix = null; + String javaHome = getJavaHome(); + if (javaHome != null) { + int index = javaHome.lastIndexOf('/'); + if (index != -1) { + javaHome = javaHome.substring(0, index); + } + } + if (jarFile.toString().startsWith(javaHome)) { + suffix = getJavaRuntimeVersion(); + } + return new File(JandexIndex.getIndexFolder().toString(), jarFile.getName() + "-" + suffix + ".jdx"); + } + +} diff --git a/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectFinderStrategy.java b/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectFinderStrategy.java new file mode 100644 index 000000000..f46142d8f --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectFinderStrategy.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * 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.gradle; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.ExecutionException; + +import org.springframework.ide.vscode.commons.languageserver.java.IJavaProjectFinderStrategy; +import org.springframework.ide.vscode.commons.util.FileUtils; +import org.springframework.ide.vscode.commons.util.StringUtil; +import org.springframework.ide.vscode.commons.util.text.IDocument; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +/** + * Tests whether document belongs to a Gradle project + * + * @author Alex Boyko + * + */ +public class GradleProjectFinderStrategy implements IJavaProjectFinderStrategy { + + private Cache cache = CacheBuilder.newBuilder().build(); + + private GradleCore gradle; + + public GradleProjectFinderStrategy(GradleCore gradle) { + this.gradle = gradle; + } + + @Override + public GradleJavaProject find(IDocument d) throws ExecutionException, URISyntaxException { + String uriStr = d.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(); + File gradlebuild = FileUtils.findFile(file, GradleCore.GRADLE_BUILD_FILE); + if (gradlebuild != null) { + return cache.get(gradlebuild.getParentFile(), () -> { + return new GradleJavaProject(gradle, gradlebuild.getParentFile()); + }); + } + } + } + return null; + } + +} diff --git a/vscode-extensions/commons/commons-gradle/src/test/java/org/springframework/ide/vscode/commons/gradle/GradleProjectTest.java b/vscode-extensions/commons/commons-gradle/src/test/java/org/springframework/ide/vscode/commons/gradle/GradleProjectTest.java new file mode 100644 index 000000000..f99c08bb8 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/java/org/springframework/ide/vscode/commons/gradle/GradleProjectTest.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * 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.gradle; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.junit.Test; + +/** + * Tests covering Gradle project data + * + * @author Alex Boyko + * + */ +public class GradleProjectTest { + + private GradleJavaProject getGradleProject(String projectName) throws Exception { + Path testProjectPath = Paths.get(GradleProjectTest.class.getResource("/" + projectName).toURI()); + return new GradleJavaProject(GradleCore.getDefault(), testProjectPath.toFile()); + } + + @Test + public void testEclipseGradleProject() throws Exception { + GradleJavaProject project = getGradleProject("empty-gradle-project"); + Set calculatedClassPath = project.getClasspath().getClasspathEntries().collect(Collectors.toSet()); + assertEquals(48, calculatedClassPath.size()); + } + + @Test + public void outputFolder() throws Exception { + GradleJavaProject project = getGradleProject("test-app-1"); + assertTrue(project.getClasspath().getOutputFolder().endsWith("bin")); + } + + @Test + public void gradleClasspathResource() throws Exception { + GradleJavaProject project = getGradleProject("test-app-1"); + List resources = project.getClasspath().getClasspathResources().collect(Collectors.toList()); + assertArrayEquals(new String[] {"test-resource-1.txt"}, resources.toArray(new String[resources.size()])); + } + +} diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/.gitignore b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/.gitignore new file mode 100644 index 000000000..c9f701048 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/.gitignore @@ -0,0 +1,25 @@ +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ \ No newline at end of file diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/build.gradle b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/build.gradle new file mode 100644 index 000000000..87b447d99 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/build.gradle @@ -0,0 +1,33 @@ +buildscript { + ext { + springBootVersion = '1.5.1.RELEASE' + } + repositories { + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") + } +} + +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'org.springframework.boot' + +jar { + baseName = 'empty-boot-1.4.0-web-app' + version = '0.0.1-SNAPSHOT' +} + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + + +dependencies { + compile('org.springframework.boot:spring-boot-starter-actuator') + compile('org.springframework.boot:spring-boot-starter-web') + testCompile('org.springframework.boot:spring-boot-starter-test') +} diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradle/wrapper/gradle-wrapper.jar b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..ca78035ef Binary files /dev/null and b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradle/wrapper/gradle-wrapper.jar differ diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradle/wrapper/gradle-wrapper.properties b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..b66f3c112 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradlew b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradlew new file mode 100755 index 000000000..27309d923 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradlew.bat b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradlew.bat new file mode 100644 index 000000000..832fdb607 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/src/main/java/com/example/EmptyGradleProjectApplication.java b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/src/main/java/com/example/EmptyGradleProjectApplication.java new file mode 100644 index 000000000..5c892a565 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/src/main/java/com/example/EmptyGradleProjectApplication.java @@ -0,0 +1,12 @@ +package com.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class EmptyGradleProjectApplication { + + public static void main(String[] args) { + SpringApplication.run(EmptyGradleProjectApplication.class, args); + } +} diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/src/main/resources/application.properties b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/src/main/resources/application.properties new file mode 100644 index 000000000..e69de29bb diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/src/test/java/com/example/EmptyGradleProjectApplicationTests.java b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/src/test/java/com/example/EmptyGradleProjectApplicationTests.java new file mode 100644 index 000000000..f2ba4bbc4 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/empty-gradle-project/src/test/java/com/example/EmptyGradleProjectApplicationTests.java @@ -0,0 +1,16 @@ +package com.example; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class EmptyGradleProjectApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/fileHashes.bin b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/fileHashes.bin new file mode 100644 index 000000000..e80e08a00 Binary files /dev/null and b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/fileHashes.bin differ diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/fileSnapshots.bin b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/fileSnapshots.bin new file mode 100644 index 000000000..15b63715c Binary files /dev/null and b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/fileSnapshots.bin differ diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/taskArtifacts.bin b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/taskArtifacts.bin new file mode 100644 index 000000000..33f6a081c Binary files /dev/null and b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/taskArtifacts.bin differ diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/taskArtifacts.lock b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/taskArtifacts.lock new file mode 100644 index 000000000..ae4ecd12e Binary files /dev/null and b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/.gradle/3.3/taskArtifacts/taskArtifacts.lock differ diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/build.gradle b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/build.gradle new file mode 100644 index 000000000..fd99219f5 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/build.gradle @@ -0,0 +1,28 @@ +/* + * This build file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java project to get you started. + * For more details take a look at the Java Quickstart chapter in the Gradle + * user guide available at https://docs.gradle.org/3.3/userguide/tutorial_java_projects.html + */ + +// Apply the java plugin to add support for Java +apply plugin: 'java' + +// In this section you declare where to find the dependencies of your project +repositories { + // Use jcenter for resolving your dependencies. + // You can declare any Maven/Ivy/file repository here. + jcenter() +} + +dependencies { + // The production code uses Guava + compile 'com.google.guava:guava:20.0' + compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '1.5.1.RELEASE' + compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.5.1.RELEASE' + + // Use JUnit test framework + testCompile 'junit:junit:4.12' +} + diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/gradle/wrapper/gradle-wrapper.properties b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..49bf4f6c9 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Feb 07 11:31:46 EST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-bin.zip diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/gradlew b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/gradlew new file mode 100755 index 000000000..4453ccea3 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/gradlew.bat b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/gradlew.bat new file mode 100644 index 000000000..f9553162f --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/settings.gradle b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/settings.gradle new file mode 100644 index 000000000..aa96911ff --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/settings.gradle @@ -0,0 +1,20 @@ +/* + * This settings file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * In a single project build this file can be empty or even removed. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user guide at https://docs.gradle.org/3.3/userguide/multi_project_builds.html + */ + +/* +// To declare projects as part of a multi-project build use the 'include' method +include 'shared' +include 'api' +include 'services:webservice' +*/ + +rootProject.name = 'test-app-1' +//org.gradle.java.home = '/Library/Java/JavaVirtualMachines/jdk1.7.0_60.jdk/Contents/Home' + diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/src/main/java/Library.java b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/src/main/java/Library.java new file mode 100644 index 000000000..fa1b41a26 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/src/main/java/Library.java @@ -0,0 +1,8 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +public class Library { + public boolean someLibraryMethod() { + return true; + } +} diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/src/test/java/LibraryTest.java b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/src/test/java/LibraryTest.java new file mode 100644 index 000000000..645740d03 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/src/test/java/LibraryTest.java @@ -0,0 +1,12 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +import org.junit.Test; +import static org.junit.Assert.*; + +public class LibraryTest { + @Test public void testSomeLibraryMethod() { + Library classUnderTest = new Library(); + assertTrue("someLibraryMethod should return 'true'", classUnderTest.someLibraryMethod()); + } +} diff --git a/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/src/test/resources/test-resource-1.txt b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/src/test/resources/test-resource-1.txt new file mode 100644 index 000000000..9dbfeeee5 --- /dev/null +++ b/vscode-extensions/commons/commons-gradle/src/test/resources/test-app-1/src/test/resources/test-resource-1.txt @@ -0,0 +1 @@ +Some text \ No newline at end of file diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java new file mode 100644 index 000000000..c90066026 --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java @@ -0,0 +1,88 @@ +package org.springframework.ide.vscode.commons.jandex; + +import java.io.File; +import java.nio.file.Path; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.springframework.ide.vscode.commons.java.IClasspath; +import org.springframework.ide.vscode.commons.java.IJavadocProvider; +import org.springframework.ide.vscode.commons.java.IType; +import org.springframework.ide.vscode.commons.util.Log; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; + +import reactor.core.publisher.Flux; +import reactor.util.function.Tuple2; + +public abstract class JandexClasspath implements IClasspath { + + public static JavadocProviderTypes providerType = JavadocProviderTypes.HTML; + + public enum JavadocProviderTypes { + JAVA_PARSER, + HTML + } + + private Supplier javaIndex; + + public JandexClasspath() { + this.javaIndex = Suppliers.memoize(() -> createIndex()); + } + + protected JandexIndex createIndex() { + Stream classpathEntries = Stream.empty(); + try { + classpathEntries = getClasspathEntries(); + } catch (Exception e) { + Log.log(e); + } + return new JandexIndex(classpathEntries.map(p -> p.toFile()).collect(Collectors.toList()), jarFile -> findIndexFile(jarFile), classpathResource -> { + switch (providerType) { + case JAVA_PARSER: + return createParserJavadocProvider(classpathResource); + default: + return createHtmlJavdocProvider(classpathResource); + } + }, getBaseIndices()); + } + + protected JandexIndex[] getBaseIndices() { + return new JandexIndex[0]; + } + + public IType findType(String fqName) { + return javaIndex.get().findType(fqName); + } + + public Flux> fuzzySearchTypes(String searchTerm, Predicate typeFilter) { + return javaIndex.get().fuzzySearchTypes(searchTerm, typeFilter); + } + + public Flux> fuzzySearchPackages(String searchTerm) { + return javaIndex.get().fuzzySearchPackages(searchTerm); + } + + public Flux allSubtypesOf(IType type) { + return javaIndex.get().allSubtypesOf(type); + } + + private File findIndexFile(File jarFile) { + File indexFolder = getIndexFolder(); + if (indexFolder == null) { + return null; + } + return new File(indexFolder.toString(), jarFile.getName() + "-" + jarFile.lastModified() + ".jdx"); + } + + protected File getIndexFolder() { + return JandexIndex.getIndexFolder(); + } + + abstract protected IJavadocProvider createParserJavadocProvider(File classpathResource); + + abstract protected IJavadocProvider createHtmlJavdocProvider(File classpathResource); + +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexIndex.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexIndex.java index 195baf290..43935a478 100644 --- a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexIndex.java +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexIndex.java @@ -54,19 +54,29 @@ import reactor.util.function.Tuple2; import reactor.util.function.Tuples; public class JandexIndex { - + + private static final String JAVA_IO_TMPDIR = "java.io.tmpdir"; + @FunctionalInterface public static interface IndexFileFinder { File findIndexFile(File jarFile); } - + @FunctionalInterface public static interface JavadocProviderFactory { IJavadocProvider createJavadocProvider(File jarContainer); } - + + public static File getIndexFolder() { + File folder = new File(System.getProperty(JAVA_IO_TMPDIR), "jandex"); + if (!folder.isDirectory()) { + folder.mkdirs(); + } + return folder; + } + private static final IJavadocProvider ABSENT_JAVADOC_PROVIDER = new IJavadocProvider() { - + @Override public IJavadoc getJavadoc(IType type) { return null; @@ -86,30 +96,31 @@ public class JandexIndex { public IJavadoc getJavadoc(IAnnotation method) { return null; } - + }; - + private Map>> index; - + private JavadocProviderFactory javadocProviderFactory; - + private Map>>> knownTypes; - + private Map>> knownPackages; - + private Cache javadocProvidersCache = CacheBuilder.newBuilder().build(); private JandexIndex[] baseIndex; - + public void setJvadocProviderFactory(JavadocProviderFactory sourceContainerProvider) { this.javadocProviderFactory = sourceContainerProvider; } - + public JavadocProviderFactory getJavadocProviderFactory() { return javadocProviderFactory; } - - public JandexIndex(Collection classpathEntries, IndexFileFinder indexFileFinder, JavadocProviderFactory javadocProviderFactory, JandexIndex... baseIndex) { + + public JandexIndex(Collection classpathEntries, IndexFileFinder indexFileFinder, + JavadocProviderFactory javadocProviderFactory, JandexIndex... baseIndex) { this.baseIndex = baseIndex; this.index = new ConcurrentHashMap<>(); this.knownTypes = new HashMap<>(); @@ -121,186 +132,185 @@ public class JandexIndex { knownPackages.put(file, Suppliers.memoize(() -> getKnownPackages(file).collect(Collectors.toList()))); }); } - + private Optional createIndex(File file, IndexFileFinder indexFileFinder) { - if (file.isFile() && file.getName().endsWith(".jar")) { + if (file != null && file.isFile() && file.getName().endsWith(".jar")) { return indexJar(file, indexFileFinder); - } else if (file.isDirectory()) { + } else if (file != null && file.isDirectory()) { return indexFolder(file); } else { return Optional.empty(); } } - + private static Optional indexFolder(File folder) { Indexer indexer = new Indexer(); - for (Iterator itr = com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(folder).iterator(); itr.hasNext();) { + for (Iterator itr = com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(folder) + .iterator(); itr.hasNext();) { File file = itr.next(); if (file.isFile() && file.getName().endsWith(".class")) { - try { - final InputStream stream = new FileInputStream(file); - try { - indexer.index(stream); - } finally { - try { - stream.close(); - } catch (Exception ignore) { - } - } - } catch (Exception e) { - Log.log(e); - } + try { + final InputStream stream = new FileInputStream(file); + try { + indexer.index(stream); + } finally { + try { + stream.close(); + } catch (Exception ignore) { + } + } + } catch (Exception e) { + Log.log(e); + } } } return Optional.of(indexer.complete()); } - + private static Optional indexJar(File file, IndexFileFinder indexFileFinder) { - File indexFile = indexFileFinder.findIndexFile(file); - if (indexFile != null) { - try { - if (indexFile.createNewFile()) { - try { - return Optional.of(JarIndexer - .createJarIndex(file, new Indexer(), indexFile, - false, false, false, System.out, System.err) - .getIndex()); - } catch (IOException e) { - Log.log("Failed to index '" + file + "'", e); - } - } else { - try { - return Optional.of(new IndexReader(new FileInputStream(indexFile)).read()); - } catch (IOException e) { - Log.log("Failed to read index file '" + indexFile + "'. Creating new index file.", e); - if (indexFile.delete()) { - return indexJar(file, indexFileFinder); - } else { - Log.log("Failed to read index file '" + indexFile); - } + File indexFile = indexFileFinder.findIndexFile(file); + if (indexFile != null) { + try { + if (indexFile.createNewFile()) { + try { + return Optional.of(JarIndexer.createJarIndex(file, new Indexer(), indexFile, false, false, + false, System.out, System.err).getIndex()); + } catch (IOException e) { + Log.log("Failed to index '" + file + "'", e); + } + } else { + try { + return Optional.of(new IndexReader(new FileInputStream(indexFile)).read()); + } catch (IOException e) { + Log.log("Failed to read index file '" + indexFile + "'. Creating new index file.", e); + if (indexFile.delete()) { + return indexJar(file, indexFileFinder); + } else { + Log.log("Failed to read index file '" + indexFile); } } - } catch (IOException e) { - Log.log("Unable to create index file '" + indexFile +"'"); - } - } else { - try { - return Optional.of(JarIndexer - .createJarIndex(file, new Indexer(), file.canWrite(), file.getParentFile().canWrite(), false) - .getIndex()); - } catch (IOException e) { - Log.log("Failed to index '" + file + "'", e); } + } catch (IOException e) { + Log.log("Unable to create index file '" + indexFile + "'"); } + } else { + try { + return Optional.of(JarIndexer + .createJarIndex(file, new Indexer(), file.canWrite(), file.getParentFile().canWrite(), false) + .getIndex()); + } catch (IOException e) { + Log.log("Failed to index '" + file + "'", e); + } + } return Optional.empty(); } public IType findType(String fqName) { return getClassByName(DotName.createSimple(fqName)); } - + IType getClassByName(DotName fqName) { // First look for type in the base index array return (baseIndex == null ? Stream.empty() - : Arrays.stream(baseIndex) - .filter(jandexIndex -> jandexIndex != null) - .map(jandexIndex -> jandexIndex.getClassByName(fqName))) - .filter(type -> type != null) - .findFirst() - // If not found look at indices owned by this JandexIndex instance - .orElseGet(() -> streamOfIndices() - .map(e -> Tuples.of(e.getT1(), e.getT2().getClassByName(fqName))) - .filter(e -> e.getT2() != null) - .map(e -> createType(e)) - .findFirst() - .orElse(null)); - + : Arrays.stream( + baseIndex) + .filter( + jandexIndex -> jandexIndex != null) + .map(jandexIndex -> jandexIndex.getClassByName(fqName))).filter(type -> type != null) + .findFirst() + // If not found look at indices owned by this + // JandexIndex instance + .orElseGet(() -> streamOfIndices() + .map(e -> Tuples.of(e.getT1(), e.getT2().getClassByName(fqName))) + .filter(e -> e.getT2() != null).map(e -> createType(e)).findFirst() + .orElse(null)); + } - + private IType createType(Tuple2 match) { File classpathResource = match.getT1(); IJavadocProvider javadocProvider = null; try { - javadocProvider = javadocProvidersCache.get(classpathResource, () -> javadocProviderFactory == null ? ABSENT_JAVADOC_PROVIDER : javadocProviderFactory.createJavadocProvider(classpathResource)); + javadocProvider = javadocProvidersCache.get(classpathResource, () -> { + IJavadocProvider provider = null; + if (javadocProviderFactory != null) { + provider = javadocProviderFactory.createJavadocProvider(classpathResource); + } + return provider == null ? ABSENT_JAVADOC_PROVIDER : provider; + }); } catch (ExecutionException e) { Log.log(e); } - return Wrappers.wrap(this, match.getT2(), javadocProvider); + return Wrappers.wrap(this, match.getT2(), javadocProvider); } - + private Stream> streamOfIndices() { - return index.entrySet().parallelStream().map(e -> Tuples.of(e.getKey(), e.getValue().get())).filter(t -> t.getT2().isPresent()).map(t -> Tuples.of(t.getT1(), t.getT2().get())); + return index.entrySet().parallelStream().map(e -> Tuples.of(e.getKey(), e.getValue().get())) + .filter(t -> t.getT2().isPresent()).map(t -> Tuples.of(t.getT1(), t.getT2().get())); } - + private Stream> getKnownTypesStream(File file) { Optional indexView = index.get(file).get(); if (indexView.isPresent()) { - return indexView.get().getKnownClasses().parallelStream().map(info -> Tuples.of(info.name().toString(), createType(Tuples.of(file, info)))); + return indexView.get().getKnownClasses().parallelStream() + .map(info -> Tuples.of(info.name().toString(), createType(Tuples.of(file, info)))); } return Stream.empty(); } - + private Stream getKnownPackages(File file) { Optional indexView = index.get(file).get(); if (indexView.isPresent()) { - return indexView.get() - .getKnownClasses() - .parallelStream() - .map(info -> { - String name = info.name().toString(); - return name.substring(0, name.lastIndexOf('.')); - }) - .distinct(); + return indexView.get().getKnownClasses().parallelStream().map(info -> { + String name = info.name().toString(); + return name.substring(0, name.lastIndexOf('.')); + }).distinct(); } return Stream.empty(); } - + public Flux> fuzzySearchTypes(String searchTerm, Predicate typeFilter) { - Flux> flux = Flux.fromIterable(knownTypes.values()) - .publishOn(Schedulers.parallel()) - .flatMap(s -> Flux.fromIterable(s.get())) - .filter(t -> typeFilter == null || typeFilter.test(t.getT2())) + Flux> flux = Flux.fromIterable(knownTypes.values()).publishOn(Schedulers.parallel()) + .flatMap(s -> Flux.fromIterable(s.get())).filter(t -> typeFilter == null || typeFilter.test(t.getT2())) .map(t -> Tuples.of(t.getT2(), FuzzyMatcher.matchScore(searchTerm, t.getT1()))) .filter(t -> t.getT2() != 0.0); if (baseIndex == null) { return flux; } else { - return Flux.merge(flux, Flux.fromArray(baseIndex).flatMap(index -> index.fuzzySearchTypes(searchTerm, typeFilter))); + return Flux.merge(flux, + Flux.fromArray(baseIndex).flatMap(index -> index.fuzzySearchTypes(searchTerm, typeFilter))); } } - + public Flux> fuzzySearchPackages(String searchTerm) { - Flux> flux = Flux.fromIterable(knownPackages.values()) - .publishOn(Schedulers.parallel()) + Flux> flux = Flux.fromIterable(knownPackages.values()).publishOn(Schedulers.parallel()) .flatMap(s -> Flux.fromIterable(s.get())) - .map(pkg -> Tuples.of(pkg, FuzzyMatcher.matchScore(searchTerm, pkg))) - .filter(t -> t.getT2() != 0.0); + .map(pkg -> Tuples.of(pkg, FuzzyMatcher.matchScore(searchTerm, pkg))).filter(t -> t.getT2() != 0.0); if (baseIndex == null) { return flux; } else { return Flux.merge(flux, Flux.fromArray(baseIndex).flatMap(index -> index.fuzzySearchPackages(searchTerm))); } } - + public Flux allSubtypesOf(IType type) { DotName name = DotName.createSimple(type.getFullyQualifiedName()); - Flux flux = Flux.fromIterable(index.keySet()) - .publishOn(Schedulers.parallel()) - .flatMap(file -> { - Optional optional = index.get(file).get(); - if (optional.isPresent()) { - return Flux.fromIterable(type.isInterface() ? optional.get().getAllKnownImplementors(name) : optional.get().getAllKnownSubclasses(name)) - .publishOn(Schedulers.parallel()) - .map(info -> createType(Tuples.of(file, info))); - } else { - return Flux.empty(); - } - }); + Flux flux = Flux.fromIterable(index.keySet()).publishOn(Schedulers.parallel()).flatMap(file -> { + Optional optional = index.get(file).get(); + if (optional.isPresent()) { + return Flux + .fromIterable(type.isInterface() ? optional.get().getAllKnownImplementors(name) + : optional.get().getAllKnownSubclasses(name)) + .publishOn(Schedulers.parallel()).map(info -> createType(Tuples.of(file, info))); + } else { + return Flux.empty(); + } + }); if (baseIndex == null) { return flux; } else { return Flux.merge(flux, Flux.fromArray(baseIndex).flatMap(index -> index.allSubtypesOf(type))); } } - + } diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IClasspath.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IClasspath.java index 81ef98d3a..a30663512 100644 --- a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IClasspath.java +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IClasspath.java @@ -11,8 +11,12 @@ package org.springframework.ide.vscode.commons.java; import java.nio.file.Path; +import java.util.function.Predicate; import java.util.stream.Stream; +import reactor.core.publisher.Flux; +import reactor.util.function.Tuple2; + /** * Classpath for a Java artifact * @@ -21,7 +25,21 @@ import java.util.stream.Stream; * */ public interface IClasspath { + + String getName(); + + boolean exists(); + IType findType(String fqName); + + Flux> fuzzySearchTypes(String searchTerm, Predicate typeFilter); + + Flux> fuzzySearchPackages(String searchTerm); + + Flux allSubtypesOf(IType type); + + Path getOutputFolder(); + /** * Classpath entries paths * diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IJavaProject.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IJavaProject.java index 0e7740556..1b9631e3e 100644 --- a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IJavaProject.java +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IJavaProject.java @@ -10,20 +10,25 @@ *******************************************************************************/ package org.springframework.ide.vscode.commons.java; -import java.util.function.Predicate; - -import reactor.core.publisher.Flux; -import reactor.util.function.Tuple2; +import org.springframework.ide.vscode.commons.javadoc.IJavadoc; public interface IJavaProject extends IJavaElement { - IType findType(String fqName); - - Flux> fuzzySearchTypes(String searchTerm, Predicate typeFilter); - - Flux> fuzzySearchPackages(String searchTerm); - - Flux allSubtypesOf(IType type); - IClasspath getClasspath(); + + @Override + default String getElementName() { + return getClasspath().getName(); + } + + @Override + default IJavadoc getJavaDoc() { + return null; + } + + @Override + default boolean exists() { + return getClasspath().exists(); + } + } diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java index 3191933a3..858c5a050 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java @@ -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 @@ -37,7 +37,6 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcil import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity; import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; import org.springframework.ide.vscode.commons.util.BadLocationException; -import org.springframework.ide.vscode.commons.util.Futures; import org.springframework.ide.vscode.commons.util.text.TextDocument; import reactor.core.publisher.Mono; @@ -118,14 +117,14 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl @Override public CompletableFuture shutdown() { - return Futures.of(null); + return CompletableFuture.completedFuture(new Object()); } @Override public void exit() { + System.exit(0); } - public Path getWorkspaceRoot() { return workspaceRoot; } diff --git a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenCore.java b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenCore.java index 18d5b06b1..c02c145d9 100644 --- a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenCore.java +++ b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenCore.java @@ -76,7 +76,6 @@ public class MavenCore { private static final String CLASSIFIER_TESTS = "tests"; private static final String CLASSIFIER_TESTSOURCES = "test-sources"; - public static final String JAVA_IO_TMPDIR = "java.io.tmpdir"; private static final String JAVA_HOME = "java.home"; private static final String JAVA_RUNTIME_VERSION = "java.runtime.version"; private static final String JAVA_BOOT_CLASS_PATH = "sun.boot.class.path"; @@ -336,18 +335,11 @@ public class MavenCore { } catch (MavenException e) { Log.log(e); } - return new File(getIndexFolder().toString(), jarFile.getName() + "-" + suffix + ".jdx"); + return new File(JandexIndex.getIndexFolder().toString(), jarFile.getName() + "-" + suffix + ".jdx"); } public JandexIndex getJavaIndexForJreLibs() { return javaCoreIndex.get(); } - public File getIndexFolder() { - File folder = new File(System.getProperty(JAVA_IO_TMPDIR), "jandex"); - if (!folder.isDirectory()) { - folder.mkdirs(); - } - return folder; - } } diff --git a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenProjectFinderStrategy.java b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenProjectFinderStrategy.java index e03d4122d..c925015dd 100644 --- a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenProjectFinderStrategy.java +++ b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenProjectFinderStrategy.java @@ -32,7 +32,13 @@ import com.google.common.cache.CacheBuilder; */ public class MavenProjectFinderStrategy implements IJavaProjectFinderStrategy { - public Cache cache = CacheBuilder.newBuilder().build(); + private Cache cache = CacheBuilder.newBuilder().build(); + + private MavenCore maven; + + public MavenProjectFinderStrategy(MavenCore maven) { + this.maven = maven; + } @Override public MavenJavaProject find(IDocument d) throws ExecutionException, URISyntaxException { @@ -46,7 +52,7 @@ public class MavenProjectFinderStrategy implements IJavaProjectFinderStrategy { File pomFile = FileUtils.findFile(file, MavenCore.POM_XML); if (pomFile != null) { return cache.get(pomFile, () -> { - return new MavenJavaProject(pomFile); + return new MavenJavaProject(maven, pomFile); }); } } diff --git a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenJavaProject.java b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenJavaProject.java index 6f496f4f8..549312c16 100644 --- a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenJavaProject.java +++ b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenJavaProject.java @@ -11,18 +11,10 @@ package org.springframework.ide.vscode.commons.maven.java; import java.io.File; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.function.Predicate; import org.springframework.ide.vscode.commons.java.IJavaProject; -import org.springframework.ide.vscode.commons.java.IType; -import org.springframework.ide.vscode.commons.javadoc.IJavadoc; import org.springframework.ide.vscode.commons.maven.MavenCore; -import reactor.core.publisher.Flux; -import reactor.util.function.Tuple2; - /** * Wrapper for Maven Core project * @@ -32,46 +24,9 @@ import reactor.util.function.Tuple2; public class MavenJavaProject implements IJavaProject { private MavenProjectClasspath classpath; - private MavenCore maven; - public MavenJavaProject(File pom) { - this.maven = MavenCore.getDefault(); - this.classpath = new MavenProjectClasspath(pom, maven); - } - - @Override - public String getElementName() { - return classpath.getName(); - } - - @Override - public IJavadoc getJavaDoc() { - return null; - } - - @Override - public boolean exists() { - return classpath.exists(); - } - - @Override - public IType findType(String fqName) { - return classpath.findType(fqName); - } - - @Override - public Flux> fuzzySearchTypes(String searchTerm, Predicate typeFilter) { - return classpath.fuzzySearchType(searchTerm, typeFilter); - } - - @Override - public Flux> fuzzySearchPackages(String searchTerm) { - return classpath.fuzzySearchPackages(searchTerm); - } - - @Override - public Flux allSubtypesOf(IType type) { - return classpath.allSubtypesOf(type); + public MavenJavaProject(MavenCore maven, File pom) { + this.classpath = new MavenProjectClasspath(maven, pom); } @Override @@ -79,8 +34,4 @@ public class MavenJavaProject implements IJavaProject { return classpath; } - public Path getOutputFolder() { - return Paths.get(new File(classpath.getOutputFolder()).toURI()); - } - } diff --git a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java index 0147bbde2..07400d374 100644 --- a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java +++ b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java @@ -19,17 +19,14 @@ import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.maven.artifact.Artifact; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.DirectoryScanner; +import org.springframework.ide.vscode.commons.jandex.JandexClasspath; import org.springframework.ide.vscode.commons.jandex.JandexIndex; -import org.springframework.ide.vscode.commons.java.IClasspath; import org.springframework.ide.vscode.commons.java.IJavadocProvider; -import org.springframework.ide.vscode.commons.java.IType; import org.springframework.ide.vscode.commons.java.parser.ParserJavadocProvider; import org.springframework.ide.vscode.commons.javadoc.HtmlJavadocProvider; import org.springframework.ide.vscode.commons.javadoc.SourceUrlProviderFromSourceContainer; @@ -40,58 +37,30 @@ import org.springframework.ide.vscode.commons.util.Log; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; -import reactor.core.publisher.Flux; -import reactor.util.function.Tuple2; - /** * Classpath for a maven project * * @author Alex Boyko * */ -public class MavenProjectClasspath implements IClasspath { - - public static JavadocProviderTypes providerType = JavadocProviderTypes.HTML; - - public enum JavadocProviderTypes { - JAVA_PARSER, -// ROASTER, - HTML - } +public class MavenProjectClasspath extends JandexClasspath { private MavenCore maven; private File pom; private Supplier projectSupplier; - private Supplier javaIndex; - public MavenProjectClasspath(File pom) { - this(pom, MavenCore.getDefault()); - } - - MavenProjectClasspath(File pom, MavenCore maven) { + MavenProjectClasspath(MavenCore maven, File pom) { + super(); this.maven = maven; this.pom = pom; this.projectSupplier = Suppliers.memoize(() -> createMavenProject()); - this.javaIndex = Suppliers.memoize(() -> { - Stream classpathEntries = Stream.empty(); - try { - classpathEntries = getClasspathEntries(); - } catch (Exception e) { - Log.log(e); - } - return new JandexIndex(classpathEntries.map(p -> p.toFile()).collect(Collectors.toList()), jarFile -> findIndexFile(jarFile), classpathResource -> { - switch (providerType) { - case JAVA_PARSER: - return createParserJavadocProvider(classpathResource); -// case ROASTER: -// return createRoasterJavadocProvider(classpathResource); - default: - return createHtmlJavdocProvider(classpathResource); - } - }, maven.getJavaIndexForJreLibs()); - }); } + @Override + protected JandexIndex[] getBaseIndices() { + return new JandexIndex[] { maven.getJavaIndexForJreLibs() }; + } + private final MavenProject createMavenProject() { try { // Read with resolved dependencies @@ -139,29 +108,9 @@ public class MavenProjectClasspath implements IClasspath { } } - public String getOutputFolder() { + public Path getOutputFolder() { MavenProject project = projectSupplier.get(); - return project == null ? null : project.getBuild().getOutputDirectory(); - } - - public IType findType(String fqName) { - return javaIndex.get().findType(fqName); - } - - public Flux> fuzzySearchType(String searchTerm, Predicate typeFilter) { - return javaIndex.get().fuzzySearchTypes(searchTerm, typeFilter); - } - - public Flux> fuzzySearchPackages(String searchTerm) { - return javaIndex.get().fuzzySearchPackages(searchTerm); - } - - public Flux allSubtypesOf(IType type) { - return javaIndex.get().allSubtypesOf(type); - } - - private File findIndexFile(File jarFile) { - return new File(maven.getIndexFolder().toString(), jarFile.getName() + "-" + jarFile.lastModified() + ".jdx"); + return project == null ? null : new File(project.getBuild().getOutputDirectory()).toPath(); } private Optional getArtifactFromJarFile(File file) throws MavenException { @@ -226,7 +175,7 @@ public class MavenProjectClasspath implements IClasspath { // } // } - private IJavadocProvider createParserJavadocProvider(File classpathResource) { + protected IJavadocProvider createParserJavadocProvider(File classpathResource) { MavenProject project = projectSupplier.get(); if (project == null) { return null; @@ -263,7 +212,7 @@ public class MavenProjectClasspath implements IClasspath { } } - private IJavadocProvider createHtmlJavdocProvider(File classpathResource) { + protected IJavadocProvider createHtmlJavdocProvider(File classpathResource) { MavenProject project = projectSupplier.get(); if (project == null) { return null; diff --git a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/FileClasspath.java b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/FileClasspath.java index c71005ded..2b2157ebe 100644 --- a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/FileClasspath.java +++ b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/FileClasspath.java @@ -10,12 +10,18 @@ *******************************************************************************/ package org.springframework.ide.vscode.commons.maven.java.classpathfile; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.function.Predicate; import java.util.stream.Stream; import org.springframework.ide.vscode.commons.java.IClasspath; +import org.springframework.ide.vscode.commons.java.IType; import org.springframework.ide.vscode.commons.maven.MavenCore; +import reactor.core.publisher.Flux; +import reactor.util.function.Tuple2; + /** * Classpath for a project containing classpath text file * @@ -41,5 +47,41 @@ public class FileClasspath implements IClasspath { public Stream getClasspathResources() { return Stream.empty(); } + + @Override + public String getName() { + return classpathFilePath.toFile().getParentFile().getName(); + } + + @Override + public boolean exists() { + return Files.exists(classpathFilePath); + } + + @Override + public IType findType(String fqName) { + //TODO: implement + return null; + } + + @Override + public Flux> fuzzySearchTypes(String searchTerm, Predicate typeFilter) { + return Flux.empty(); + } + + @Override + public Flux> fuzzySearchPackages(String searchTerm) { + return Flux.empty(); + } + + @Override + public Flux allSubtypesOf(IType type) { + return Flux.empty(); + } + + @Override + public Path getOutputFolder() { + return null; + } } diff --git a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/JavaProjectWithClasspathFile.java b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/JavaProjectWithClasspathFile.java index 90725959d..808b80a9d 100644 --- a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/JavaProjectWithClasspathFile.java +++ b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/JavaProjectWithClasspathFile.java @@ -12,15 +12,9 @@ package org.springframework.ide.vscode.commons.maven.java.classpathfile; import java.io.File; import java.nio.file.Paths; -import java.util.function.Predicate; import org.springframework.ide.vscode.commons.java.IClasspath; import org.springframework.ide.vscode.commons.java.IJavaProject; -import org.springframework.ide.vscode.commons.java.IType; -import org.springframework.ide.vscode.commons.javadoc.IJavadoc; - -import reactor.core.publisher.Flux; -import reactor.util.function.Tuple2; /** * Java project that contains classpath text file @@ -38,42 +32,6 @@ public class JavaProjectWithClasspathFile implements IJavaProject { this.classpath = new FileClasspath(Paths.get(cpFile.toURI())); } - @Override - public String getElementName() { - return cpFile.getParentFile().getName(); - } - - @Override - public IJavadoc getJavaDoc() { - return null; - } - - @Override - public boolean exists() { - return cpFile.exists(); - } - - @Override - public IType findType(String fqName) { - //TODO: implement - return null; - } - - @Override - public Flux> fuzzySearchTypes(String searchTerm, Predicate typeFilter) { - return Flux.empty(); - } - - @Override - public Flux> fuzzySearchPackages(String searchTerm) { - return Flux.empty(); - } - - @Override - public Flux allSubtypesOf(IType type) { - return Flux.empty(); - } - @Override public IClasspath getClasspath() { return classpath; diff --git a/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/HtmlJavadocTest.java b/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/HtmlJavadocTest.java index 5995db438..ffcd2e6ba 100644 --- a/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/HtmlJavadocTest.java +++ b/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/HtmlJavadocTest.java @@ -21,13 +21,13 @@ import java.util.stream.Stream; import org.junit.Assume; import org.junit.Test; +import org.springframework.ide.vscode.commons.jandex.JandexClasspath; +import org.springframework.ide.vscode.commons.jandex.JandexClasspath.JavadocProviderTypes; import org.springframework.ide.vscode.commons.java.IField; import org.springframework.ide.vscode.commons.java.IMethod; import org.springframework.ide.vscode.commons.java.IType; import org.springframework.ide.vscode.commons.javadoc.IJavadoc; import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject; -import org.springframework.ide.vscode.commons.maven.java.MavenProjectClasspath; -import org.springframework.ide.vscode.commons.maven.java.MavenProjectClasspath.JavadocProviderTypes; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; @@ -37,10 +37,10 @@ public class HtmlJavadocTest { private static Supplier projectSupplier = Suppliers.memoize(() -> { Path testProjectPath; try { - MavenProjectClasspath.providerType = JavadocProviderTypes.HTML; + JandexClasspath.providerType = JavadocProviderTypes.HTML; testProjectPath = Paths.get(HtmlJavadocTest.class.getResource("/gs-rest-service-cors-boot-1.4.1-with-classpath-file").toURI()); MavenBuilder.newBuilder(testProjectPath).clean().pack().javadoc().skipTests().execute(); - return new MavenJavaProject(testProjectPath.resolve(MavenCore.POM_XML).toFile()); + return new MavenJavaProject(MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile()); } catch (Exception e) { return null; } @@ -52,7 +52,7 @@ public class HtmlJavadocTest { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("java.util.Map"); + IType type = project.getClasspath().findType("java.util.Map"); assertNotNull(type); String expected = String.join("\n", "
    An object that maps keys to values. A map cannot contain duplicate keys;", @@ -68,7 +68,7 @@ public class HtmlJavadocTest { Assume.assumeTrue(javaVersionHigherThan(6)); MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("java.util.ArrayList"); + IType type = project.getClasspath().findType("java.util.ArrayList"); assertNotNull(type); IMethod method = type.getMethod("", Stream.empty()); assertNotNull(method); @@ -86,7 +86,7 @@ public class HtmlJavadocTest { public void html_testEmptyJavadocClass() throws Exception { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("hello.Application"); + IType type = project.getClasspath().findType("hello.Application"); assertNotNull(type); assertNull(type.getJavaDoc()); } @@ -95,7 +95,7 @@ public class HtmlJavadocTest { public void html_testFieldAndMethodJavadocForJar() throws Exception { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("org.springframework.boot.SpringApplication"); + IType type = project.getClasspath().findType("org.springframework.boot.SpringApplication"); assertNotNull(type); IField field = type.getField("BANNER_LOCATION_PROPERTY_VALUE"); @@ -135,7 +135,7 @@ public class HtmlJavadocTest { public void html_testInnerClassJavadocForOutputFolder() throws Exception { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("hello.Greeting$TestInnerClass"); + IType type = project.getClasspath().findType("hello.Greeting$TestInnerClass"); assertNotNull(type); IJavadoc javaDoc = type.getJavaDoc(); assertNotNull(javaDoc); @@ -168,7 +168,7 @@ public class HtmlJavadocTest { public void html_testInnerClassLevel2_JavadocForOutputFolder() throws Exception { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("hello.Greeting$TestInnerClass$TestInnerClassLevel2"); + IType type = project.getClasspath().findType("hello.Greeting$TestInnerClass$TestInnerClassLevel2"); assertNotNull(type); IJavadoc javaDoc = type.getJavaDoc(); assertNotNull(javaDoc); @@ -200,7 +200,7 @@ public class HtmlJavadocTest { @Test public void html_testJavadocOutputFolder() throws Exception { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("hello.Greeting"); + IType type = project.getClasspath().findType("hello.Greeting"); assertNotNull(type); String expected = "
    Comment for Greeting class
    "; @@ -237,7 +237,7 @@ public class HtmlJavadocTest { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("java.util.ArrayList"); + IType type = project.getClasspath().findType("java.util.ArrayList"); assertNotNull(type); IMethod method = type.getMethod("size", Stream.empty()); assertNotNull(method); @@ -258,7 +258,7 @@ public class HtmlJavadocTest { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("java.util.Map$Entry"); + IType type = project.getClasspath().findType("java.util.Map$Entry"); assertNotNull(type); String expected = String.join("\n", "
    A map entry (key-value pair). The Map.entrySet method returns", @@ -272,7 +272,7 @@ public class HtmlJavadocTest { public void html_testNoJavadocClass() throws Exception { MavenJavaProject project = projectSupplier.get();; - IType type = project.findType("hello.GreetingController"); + IType type = project.getClasspath().findType("hello.GreetingController"); assertNotNull(type); assertNull(type.getJavaDoc()); } @@ -281,7 +281,7 @@ public class HtmlJavadocTest { public void html_testNoJavadocField() throws Exception { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("hello.GreetingController"); + IType type = project.getClasspath().findType("hello.GreetingController"); assertNotNull(type); IField field = type.getField("template"); assertNotNull(field); @@ -302,7 +302,7 @@ public class HtmlJavadocTest { public void html_testNoJavadocMethod() throws Exception { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("hello.Application"); + IType type = project.getClasspath().findType("hello.Application"); assertNotNull(type); IMethod method = type.getMethod("corsConfigurer", Stream.empty()); assertNotNull(method); diff --git a/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java b/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java index d443adb4f..0fe710e24 100644 --- a/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java +++ b/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java @@ -45,7 +45,7 @@ public class JavaIndexTest { public MavenJavaProject load(String projectName) throws Exception { Path testProjectPath = Paths.get(DependencyTreeTest.class.getResource("/" + projectName).toURI()); MavenBuilder.newBuilder(testProjectPath).clean().pack().javadoc().skipTests().execute(); - return new MavenJavaProject(testProjectPath.resolve(MavenCore.POM_XML).toFile()); + return new MavenJavaProject(MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile()); } }); @@ -83,28 +83,28 @@ public class JavaIndexTest { @Test public void findClassInJar() throws Exception { MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file"); - IType type = project.findType("org.springframework.test.web.client.ExpectedCount"); + IType type = project.getClasspath().findType("org.springframework.test.web.client.ExpectedCount"); assertNotNull(type); } @Test public void findClassInOutputFolder() throws Exception { MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file"); - IType type = project.findType("hello.Greeting"); + IType type = project.getClasspath().findType("hello.Greeting"); assertNotNull(type); } @Test public void classNotFound() throws Exception { MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file"); - IType type = project.findType("hello.NonExistentClass"); + IType type = project.getClasspath().findType("hello.NonExistentClass"); assertNull(type); } @Test public void voidMethodNoParams() throws Exception { MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file"); - IType type = project.findType("java.util.ArrayList"); + IType type = project.getClasspath().findType("java.util.ArrayList"); assertNotNull(type); IMethod m = type.getMethod("clear", Stream.empty()); assertEquals("clear", m.getElementName()); @@ -115,7 +115,7 @@ public class JavaIndexTest { @Test public void voidConstructor() throws Exception { MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file"); - IType type = project.findType("java.util.ArrayList"); + IType type = project.getClasspath().findType("java.util.ArrayList"); assertNotNull(type); IMethod m = type.getMethod("", Stream.empty()); assertEquals(type.getElementName(), m.getElementName()); @@ -126,7 +126,7 @@ public class JavaIndexTest { @Test public void constructorMethodWithParams() throws Exception { MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file"); - IType type = project.findType("java.util.ArrayList"); + IType type = project.getClasspath().findType("java.util.ArrayList"); assertNotNull(type); IMethod m = type.getMethod("", Stream.of(IPrimitiveType.INT)); assertEquals(m.getDeclaringType().getElementName(), m.getElementName()); diff --git a/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/SourceJavadocTest.java b/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/SourceJavadocTest.java index f196b9d37..cffcb6301 100644 --- a/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/SourceJavadocTest.java +++ b/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/SourceJavadocTest.java @@ -19,12 +19,12 @@ import java.nio.file.Paths; import java.util.stream.Stream; import org.junit.Test; +import org.springframework.ide.vscode.commons.jandex.JandexClasspath; +import org.springframework.ide.vscode.commons.jandex.JandexClasspath.JavadocProviderTypes; import org.springframework.ide.vscode.commons.java.IField; import org.springframework.ide.vscode.commons.java.IMethod; import org.springframework.ide.vscode.commons.java.IType; import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject; -import org.springframework.ide.vscode.commons.maven.java.MavenProjectClasspath; -import org.springframework.ide.vscode.commons.maven.java.MavenProjectClasspath.JavadocProviderTypes; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; @@ -34,9 +34,9 @@ public class SourceJavadocTest { private static Supplier projectSupplier = Suppliers.memoize(() -> { Path testProjectPath; try { - MavenProjectClasspath.providerType = JavadocProviderTypes.JAVA_PARSER; + JandexClasspath.providerType = JavadocProviderTypes.JAVA_PARSER; testProjectPath = Paths.get(SourceJavadocTest.class.getResource("/gs-rest-service-cors-boot-1.4.1-with-classpath-file").toURI()); - return new MavenJavaProject(testProjectPath.resolve(MavenCore.POM_XML).toFile()); + return new MavenJavaProject(MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile()); } catch (Exception e) { return null; } @@ -46,7 +46,7 @@ public class SourceJavadocTest { public void parser_testClassJavadocForJar() throws Exception { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener"); + IType type = project.getClasspath().findType("org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener"); assertNotNull(type); String expected = String.join("\n", "/**", @@ -54,7 +54,7 @@ public class SourceJavadocTest { ); assertEquals(expected, type.getJavaDoc().raw().trim().substring(0, expected.length())); - type = project.findType("org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener$LiquibasePresent"); + type = project.getClasspath().findType("org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener$LiquibasePresent"); assertNotNull(type); expected = String.join("\n", "/**", @@ -67,7 +67,7 @@ public class SourceJavadocTest { @Test public void parser_testClassJavadocForOutputFolder() throws Exception { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("hello.Greeting"); + IType type = project.getClasspath().findType("hello.Greeting"); assertNotNull(type); String expected = String.join("\n", @@ -100,7 +100,7 @@ public class SourceJavadocTest { public void parser_testFieldAndMethodJavadocForJar() throws Exception { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("org.springframework.boot.SpringApplication"); + IType type = project.getClasspath().findType("org.springframework.boot.SpringApplication"); assertNotNull(type); IField field = type.getField("BANNER_LOCATION_PROPERTY_VALUE"); @@ -124,7 +124,7 @@ public class SourceJavadocTest { @Test public void parser_testInnerClassJavadocForOutputFolder() throws Exception { MavenJavaProject project = projectSupplier.get(); - IType type = project.findType("hello.Greeting$TestInnerClass"); + IType type = project.getClasspath().findType("hello.Greeting$TestInnerClass"); assertNotNull(type); assertEquals("/**\n * Comment for inner class\n */", type.getJavaDoc().raw().trim()); diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/util/FuzzyMap.java b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/FuzzyMap.java similarity index 98% rename from vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/util/FuzzyMap.java rename to vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/FuzzyMap.java index ac551346f..4df5f91a9 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/util/FuzzyMap.java +++ b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/FuzzyMap.java @@ -8,7 +8,7 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.boot.metadata.util; +package org.springframework.ide.vscode.commons.util; import java.util.ArrayList; import java.util.Collection; diff --git a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/metadata/FuzzyMapTest.java b/vscode-extensions/commons/commons-util/src/test/java/org/springframework/ide/vscode/commons/util/FuzzyMapTest.java similarity index 93% rename from vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/metadata/FuzzyMapTest.java rename to vscode-extensions/commons/commons-util/src/test/java/org/springframework/ide/vscode/commons/util/FuzzyMapTest.java index 0d5f9d812..8ceac034e 100644 --- a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/metadata/FuzzyMapTest.java +++ b/vscode-extensions/commons/commons-util/src/test/java/org/springframework/ide/vscode/commons/util/FuzzyMapTest.java @@ -8,18 +8,17 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.boot.metadata; +package org.springframework.ide.vscode.commons.util; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.junit.Test; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap.Match; -import org.springframework.ide.vscode.commons.util.FuzzyMatcher; +import org.springframework.ide.vscode.commons.util.FuzzyMap.Match; public class FuzzyMapTest { diff --git a/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java b/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java index 812ab72cd..dc1e8e8dd 100644 --- a/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java +++ b/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java @@ -302,6 +302,7 @@ public class LanguageServerHarness { TextDocumentPositionParams params = new TextDocumentPositionParams(); params.setPosition(cursor); params.setTextDocument(doc.getId()); + server.waitForReconcile(); return server.getTextDocumentService().completion(params).get(); } diff --git a/vscode-extensions/commons/pom.xml b/vscode-extensions/commons/pom.xml index 43dbed3a4..a3ccd0ed5 100644 --- a/vscode-extensions/commons/pom.xml +++ b/vscode-extensions/commons/pom.xml @@ -18,8 +18,7 @@ java-properties commons-cf commons-maven - - + commons-gradle @@ -73,13 +72,13 @@ 1.17 4.11 3.5.2 - 1.7.21 + 1.7.22 19.0 2.5.0 2.10 0.1.0 - 3.0.4.RELEASE + 3.0.5.RELEASE 0.6.0.RELEASE 2.4.0.BUILD-SNAPSHOT diff --git a/vscode-extensions/vscode-boot-java/lib/Main.ts b/vscode-extensions/vscode-boot-java/lib/Main.ts index 62c553daf..944b0ca6d 100644 --- a/vscode-extensions/vscode-boot-java/lib/Main.ts +++ b/vscode-extensions/vscode-boot-java/lib/Main.ts @@ -19,7 +19,7 @@ export function activate(context: VSCode.ExtensionContext) { let options: commons.ActivatorOptions = { DEBUG: false, - CONNECT_TO_LS: true, + CONNECT_TO_LS: false, extensionId: 'vscode-boot-java', fatJarFile: 'target/vscode-boot-java-0.0.1-SNAPSHOT.jar', clientOptions: { diff --git a/vscode-extensions/vscode-boot-java/pom.xml b/vscode-extensions/vscode-boot-java/pom.xml index 4457b0e29..de3f34aba 100644 --- a/vscode-extensions/vscode-boot-java/pom.xml +++ b/vscode-extensions/vscode-boot-java/pom.xml @@ -4,14 +4,14 @@ 4.0.0 vscode-boot-java jar - + org.springframework.ide.vscode commons-parent 0.0.1-SNAPSHOT ../commons/pom.xml - + @@ -23,7 +23,7 @@ - + distribution-repository @@ -31,19 +31,24 @@ file://${basedir}/dist - + org.springframework.ide.vscode commons-maven ${project.version} + + org.springframework.ide.vscode + commons-gradle + ${project.version} + org.springframework.ide.vscode commons-language-server ${project.version} - + org.eclipse.jdt @@ -57,6 +62,12 @@ 2.4 + + org.springframework.boot + spring-boot-configuration-metadata + 1.5.1.RELEASE + + org.springframework.ide.vscode @@ -64,7 +75,7 @@ ${project.version} test - + @@ -102,6 +113,6 @@ - + diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java index 59e1abd98..94c306f0b 100644 --- a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java @@ -15,15 +15,21 @@ import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.TextDocumentSyncKind; import org.springframework.ide.vscode.boot.java.completions.BootJavaCompletionEngine; import org.springframework.ide.vscode.boot.java.completions.BootJavaReconcileEngine; +import org.springframework.ide.vscode.boot.java.hover.BootJavaHoverProvider; +import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; +import org.springframework.ide.vscode.commons.gradle.GradleCore; +import org.springframework.ide.vscode.commons.gradle.GradleProjectFinderStrategy; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter; import org.springframework.ide.vscode.commons.languageserver.java.DefaultJavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.java.IJavaProjectFinderStrategy; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine; +import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; import org.springframework.ide.vscode.commons.maven.JavaProjectWithClasspathFileFinderStrategy; +import org.springframework.ide.vscode.commons.maven.MavenCore; import org.springframework.ide.vscode.commons.maven.MavenProjectFinderStrategy; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -35,15 +41,14 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument; public class BootJavaLanguageServer extends SimpleLanguageServer { public static final JavaProjectFinder DEFAULT_PROJECT_FINDER = new DefaultJavaProjectFinder(new IJavaProjectFinderStrategy[] { - new MavenProjectFinderStrategy(), + new MavenProjectFinderStrategy(MavenCore.getDefault()), + new GradleProjectFinderStrategy(GradleCore.getDefault()), new JavaProjectWithClasspathFileFinderStrategy() }); - private final JavaProjectFinder javaProjectFinder; private final VscodeCompletionEngineAdapter completionEngine; - public BootJavaLanguageServer(JavaProjectFinder javaProjectFinder) { - this.javaProjectFinder = javaProjectFinder; + public BootJavaLanguageServer(JavaProjectFinder javaProjectFinder, SpringPropertyIndexProvider indexProvider) { SimpleTextDocumentService documents = getTextDocumentService(); IReconcileEngine reconcileEngine = new BootJavaReconcileEngine(); @@ -52,11 +57,14 @@ public class BootJavaLanguageServer extends SimpleLanguageServer { validateWith(doc, reconcileEngine); }); - ICompletionEngine bootCompletionEngine = new BootJavaCompletionEngine(javaProjectFinder); + ICompletionEngine bootCompletionEngine = new BootJavaCompletionEngine(javaProjectFinder, indexProvider); completionEngine = new VscodeCompletionEngineAdapter(this, bootCompletionEngine); completionEngine.setMaxCompletionsNumber(100); documents.onCompletion(completionEngine::getCompletions); documents.onCompletionResolve(completionEngine::resolveCompletion); + + HoverHandler hoverInfoProvider = new BootJavaHoverProvider(this, javaProjectFinder); + documents.onHover(hoverInfoProvider); } public void setMaxCompletionsNumber(int number) { @@ -71,6 +79,7 @@ public class BootJavaLanguageServer extends SimpleLanguageServer { CompletionOptions completionProvider = new CompletionOptions(); completionProvider.setResolveProvider(false); c.setCompletionProvider(completionProvider); + c.setHoverProvider(true); return c; } diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/Main.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/Main.java index d8b545050..a1a5664de 100644 --- a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/Main.java +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/Main.java @@ -12,6 +12,7 @@ package org.springframework.ide.vscode.boot.java; import java.io.IOException; +import org.springframework.ide.vscode.boot.metadata.DefaultSpringPropertyIndexProvider; import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; @@ -26,7 +27,8 @@ public class Main { public static void main(String[] args) throws IOException, InterruptedException { LaunguageServerApp.start(() -> { JavaProjectFinder javaProjectFinder = BootJavaLanguageServer.DEFAULT_PROJECT_FINDER; - SimpleLanguageServer server = new BootJavaLanguageServer(javaProjectFinder); + DefaultSpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(javaProjectFinder); + SimpleLanguageServer server = new BootJavaLanguageServer(javaProjectFinder, indexProvider); return server; }); } diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/BootJavaCompletionEngine.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/BootJavaCompletionEngine.java index 8d20b070c..6411c5e39 100644 --- a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/BootJavaCompletionEngine.java +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/BootJavaCompletionEngine.java @@ -25,6 +25,7 @@ import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.NodeFinder; +import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.commons.java.IClasspath; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; @@ -38,11 +39,14 @@ import org.springframework.ide.vscode.commons.util.text.IDocument; public class BootJavaCompletionEngine implements ICompletionEngine { private static final String SPRING_SCOPE = "org.springframework.context.annotation.Scope"; + private static final String SPRING_VALUE = "org.springframework.beans.factory.annotation.Value"; private JavaProjectFinder projectFinder; + private SpringPropertyIndexProvider indexProvider; - public BootJavaCompletionEngine(JavaProjectFinder projectFinder) { + public BootJavaCompletionEngine(JavaProjectFinder projectFinder, SpringPropertyIndexProvider indexProvider) { this.projectFinder = projectFinder; + this.indexProvider = indexProvider; } @Override @@ -105,6 +109,9 @@ public class BootJavaCompletionEngine implements ICompletionEngine { if (type.getQualifiedName().equals(SPRING_SCOPE)) { new ScopeCompletionProcessor().collectCompletionsForScopeAnnotation(node, annotation, type, completions, offset, doc); } + else if (type.getQualifiedName().equals(SPRING_VALUE)) { + new ValueCompletionProcessor(indexProvider.getIndex(doc)).collectCompletionsForValueAnnotation(node, annotation, type, completions, offset, doc); + } } private String[] getClasspathEntries(IDocument doc) throws Exception { diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/ValueCompletionProcessor.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/ValueCompletionProcessor.java new file mode 100644 index 000000000..f0bfa5194 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/ValueCompletionProcessor.java @@ -0,0 +1,180 @@ +/******************************************************************************* + * 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.boot.java.completions; + +import static org.springframework.ide.vscode.commons.util.StringUtil.camelCaseToHyphens; + +import java.util.List; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.Annotation; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.MemberValuePair; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; +import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.util.BadLocationException; +import org.springframework.ide.vscode.commons.util.FuzzyMap; +import org.springframework.ide.vscode.commons.util.FuzzyMap.Match; +import org.springframework.ide.vscode.commons.util.text.IDocument; + +/** + * @author Martin Lippert + */ +public class ValueCompletionProcessor { + + private FuzzyMap index; + + public ValueCompletionProcessor(FuzzyMap index) { + this.index = index; + } + + public void collectCompletionsForValueAnnotation(ASTNode node, Annotation annotation, ITypeBinding type, + List completions, int offset, IDocument doc) { + + try { + // case: @Value(<*>) + if (node == annotation && doc.get(offset - 1, 2).endsWith("()")) { + List> matches = findMatches(""); + + for (Match match : matches) { + + DocumentEdits edits = new DocumentEdits(doc); + edits.replace(offset, offset, "\"${" + match.data.getId() + "}\""); + + ValuePropertyKeyProposal proposal = new ValuePropertyKeyProposal(edits, match.data.getId(), match.data.getName(), null); + completions.add(proposal); + } + } + // case: @Value(prefix<*>) + else if (node instanceof SimpleName && node.getParent() instanceof Annotation) { + computeProposalsForSimpleName(node, completions, offset, doc); + } + // case: @Value(value=<*>) + else if (node instanceof SimpleName && node.getParent() instanceof MemberValuePair + && "value".equals(((MemberValuePair)node.getParent()).getName().toString())) { + computeProposalsForSimpleName(node, completions, offset, doc); + } + // case: @Value("prefix<*>") + else if (node instanceof StringLiteral && node.getParent() instanceof Annotation) { + if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { + computeProposalsForStringLiteral(node, completions, offset, doc); + } + } + // case: @Value(value="prefix<*>") + else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair + && "value".equals(((MemberValuePair)node.getParent()).getName().toString())) { + if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { + computeProposalsForStringLiteral(node, completions, offset, doc); + } + } + } + catch (Exception e) { + e.printStackTrace(); + } + } + + private void computeProposalsForSimpleName(ASTNode node, List completions, int offset, + IDocument doc) { + String prefix = identifyPropertyPrefix(node.toString(), offset - node.getStartPosition()); + + int startOffset = node.getStartPosition(); + int endOffset = node.getStartPosition() + node.getLength(); + + String proposalPrefix = "\""; + String proposalPostfix = "\""; + + List> matches = findMatches(prefix); + + for (Match match : matches) { + + DocumentEdits edits = new DocumentEdits(doc); + edits.replace(startOffset, endOffset, proposalPrefix + "${" + match.data.getId() + "}" + proposalPostfix); + + ValuePropertyKeyProposal proposal = new ValuePropertyKeyProposal(edits, match.data.getId(), match.data.getName(), null); + completions.add(proposal); + } + } + + private void computeProposalsForStringLiteral(ASTNode node, List completions, int offset, + IDocument doc) throws BadLocationException { + String prefix = identifyPropertyPrefix(doc.get(node.getStartPosition() + 1, offset - (node.getStartPosition() + 1)), offset - (node.getStartPosition() + 1)); + + int startOffset = offset - prefix.length(); + int endOffset = offset; + + String prePrefix = doc.get(node.getStartPosition() + 1, offset - prefix.length() - node.getStartPosition() - 1); + + String preCompletion; + if (prePrefix.endsWith("${")) { + preCompletion = ""; + } + else if (prePrefix.endsWith("$")) { + preCompletion = "{"; + } + else { + preCompletion = "${"; + } + + String fullNodeContent = doc.get(node.getStartPosition(), node.getLength()); + String postCompletion = isClosingBracketMissing(fullNodeContent + preCompletion) ? "}" : ""; + + List> matches = findMatches(prefix); + + for (Match match : matches) { + + DocumentEdits edits = new DocumentEdits(doc); + edits.replace(startOffset, endOffset, preCompletion + match.data.getId() + postCompletion); + + ValuePropertyKeyProposal proposal = new ValuePropertyKeyProposal(edits, match.data.getId(), match.data.getName(), null); + completions.add(proposal); + } + } + + private boolean isClosingBracketMissing(String fullNodeContent) { + int bracketOpens = 0; + + for (int i = 0; i < fullNodeContent.length(); i++) { + if (fullNodeContent.charAt(i) == '{') { + bracketOpens++; + } + else if (fullNodeContent.charAt(i) == '}') { + bracketOpens--; + } + } + + return bracketOpens > 0; + } + + public String identifyPropertyPrefix(String nodeContent, int offset) { + String result = nodeContent.substring(0, offset); + + int i = offset - 1; + while (i >= 0) { + char c = nodeContent.charAt(i); + if (c == '}' || c == '{' || c == '$' || c == '#') { + result = result.substring(i + 1, offset); + break; + } + i--; + } + + return result; + } + + private List> findMatches(String prefix) { + List> matches = index.find(camelCaseToHyphens(prefix)); + return matches; + } + +} diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/ValuePropertyKeyProposal.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/ValuePropertyKeyProposal.java new file mode 100644 index 000000000..3ecf24c09 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/ValuePropertyKeyProposal.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * 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.boot.java.completions; + +import org.eclipse.lsp4j.CompletionItemKind; +import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.util.Renderable; +import org.springframework.ide.vscode.commons.util.text.IDocument; + +/** + * @author Martin Lippert + */ +public class ValuePropertyKeyProposal implements ICompletionProposal { + + private DocumentEdits edits; + private String label; + private String detail; + private Renderable documentation; + + public ValuePropertyKeyProposal(DocumentEdits edits, String label, String detail, Renderable documentation) { + this.edits = edits; + this.label = label; + this.detail = detail; + this.documentation = documentation; + } + + @Override + public ICompletionProposal deemphasize() { + return null; + } + + @Override + public String getLabel() { + return this.label; + } + + @Override + public CompletionItemKind getKind() { + return CompletionItemKind.Property; + } + + @Override + public DocumentEdits getTextEdit() { + return this.edits; + } + + @Override + public String getDetail() { + return this.detail; + } + + @Override + public Renderable getDocumentation() { + return this.documentation; + } + +} diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/hover/BootJavaHoverProvider.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/hover/BootJavaHoverProvider.java new file mode 100644 index 000000000..f6b7d3379 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/hover/BootJavaHoverProvider.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * 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.boot.java.hover; + +import java.nio.file.Path; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.Annotation; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.NodeFinder; +import org.eclipse.lsp4j.Hover; +import org.eclipse.lsp4j.TextDocumentPositionParams; +import org.springframework.ide.vscode.commons.java.IClasspath; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; +import org.springframework.ide.vscode.commons.util.text.IDocument; +import org.springframework.ide.vscode.commons.util.text.TextDocument; + +/** + * @author Martin Lippert + */ +public class BootJavaHoverProvider implements HoverHandler { + + private static final String SPRING_VALUE = "org.springframework.beans.factory.annotation.Value"; + + private JavaProjectFinder projectFinder; + private SimpleLanguageServer server; + + public BootJavaHoverProvider(SimpleLanguageServer server, JavaProjectFinder projectFinder) { + this.server = server; + this.projectFinder = projectFinder; + } + + @Override + public CompletableFuture handle(TextDocumentPositionParams params) { + SimpleTextDocumentService documents = server.getTextDocumentService(); + TextDocument doc = documents.get(params).copy(); + if (doc != null) { + try { + int offset = doc.toOffset(params.getPosition()); + CompletableFuture hoverResult = provideHover(doc, offset); + if (hoverResult != null) { + return hoverResult; + } + } + catch (Exception e) { + } + } + + return SimpleTextDocumentService.NO_HOVER; + } + + private CompletableFuture provideHover(TextDocument document, int offset) throws Exception { + ASTParser parser = ASTParser.newParser(AST.JLS8); + Map options = JavaCore.getOptions(); + JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options); + parser.setCompilerOptions(options); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + parser.setStatementsRecovery(true); + parser.setBindingsRecovery(true); + parser.setResolveBindings(true); + + String[] classpathEntries = getClasspathEntries(document); + String[] sourceEntries = new String[] {}; + parser.setEnvironment(classpathEntries, sourceEntries, null, true); + + String docURI = document.getUri(); + String unitName = docURI.substring(docURI.lastIndexOf("/")); + parser.setUnitName(unitName); + parser.setSource(document.get(0, document.getLength()).toCharArray()); + + CompilationUnit cu = (CompilationUnit) parser.createAST(null); + ASTNode node = NodeFinder.perform(cu, offset, 0); + + if (node != null) { + System.out.println("AST node found: " + node.getClass().getName()); + return provideHoverForAnnotation(node, offset, document); + } + + return null; + } + + private CompletableFuture provideHoverForAnnotation(ASTNode node, int offset, TextDocument doc) { + Annotation annotation = null; + ASTNode exactNode = node; + + while (node != null && !(node instanceof Annotation)) { + node = node.getParent(); + } + + if (node != null) { + annotation = (Annotation) node; + ITypeBinding type = annotation.resolveTypeBinding(); + if (type != null) { + String qualifiedName = type.getQualifiedName(); + if (qualifiedName != null && qualifiedName.startsWith("org.springframework")) { + return provideHoverForSpringAnnotation(exactNode, annotation, type, offset, doc); + } + } + } + + return null; + } + + private CompletableFuture provideHoverForSpringAnnotation(ASTNode node, Annotation annotation, ITypeBinding type, int offset, TextDocument doc) { + if (type.getQualifiedName().equals(SPRING_VALUE)) { + return new ValueHoverProvider().provideHoverForValueAnnotation(node, annotation, type, offset, doc); + } + + return null; + } + + private String[] getClasspathEntries(IDocument doc) throws Exception { + IJavaProject project = this.projectFinder.find(doc); + IClasspath classpath = project.getClasspath(); + Stream classpathEntries = classpath.getClasspathEntries(); + return classpathEntries + .filter(path -> path.toFile().exists()) + .map(path -> path.toAbsolutePath().toString()).toArray(String[]::new); + } + +} diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/hover/ValueHoverProvider.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/hover/ValueHoverProvider.java new file mode 100644 index 000000000..08115e1d6 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/hover/ValueHoverProvider.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * 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.boot.java.hover; + +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.apache.commons.io.IOUtils; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.Annotation; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.MemberValuePair; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.lsp4j.Hover; +import org.eclipse.lsp4j.Range; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.springframework.ide.vscode.commons.util.text.TextDocument; + +/** + * @author Martin Lippert + */ +public class ValueHoverProvider { + + public CompletableFuture provideHoverForValueAnnotation(ASTNode node, Annotation annotation, + ITypeBinding type, int offset, TextDocument doc) { + + try { + // case: @Value("prefix<*>") + if (node instanceof StringLiteral && node.getParent() instanceof Annotation) { + if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { + return provideHover(node.toString(), offset - node.getStartPosition(), node.getStartPosition(), doc); + } + } + // case: @Value(value="prefix<*>") + else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair + && "value".equals(((MemberValuePair)node.getParent()).getName().toString())) { + if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { + return provideHover(node.toString(), offset - node.getStartPosition(), node.getStartPosition(), doc); + } + } + } + catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + private CompletableFuture provideHover(String value, int offset, int nodeStartOffset, TextDocument doc) { + + try { + LocalRange range = getPropertyRange(value, offset); + if (range != null) { + String propertyKey = value.substring(range.getStart(), range.getEnd()); + + JSONObject properties = getPropertiesFromProcess(); + if (propertyKey != null && properties != null) { + Iterator keys = properties.keys(); + while (keys.hasNext()) { + String key = (String) keys.next(); + JSONObject props = properties.getJSONObject(key); + + if (props.has(propertyKey)) { + String propertyValue = props.getString(propertyKey); + + Range hoverRange = doc.toRange(nodeStartOffset + range.getStart(), range.getEnd() - range.getStart()); + + Hover hover = new Hover(); + List hoverContent = new ArrayList<>(); + + hoverContent.add("property value for " + propertyKey); + hoverContent.add(propertyValue); + hoverContent.add("coming from:"); + hoverContent.add(key); + + hover.setContents(hoverContent); + hover.setRange(hoverRange); + + return CompletableFuture.completedFuture(hover); + } + } + } + } + } + catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + public JSONObject getPropertiesFromProcess() { + try { + URL url = new URL("http://localhost:8080/env"); + + URLConnection con = url.openConnection(); + InputStream in = con.getInputStream(); + String encoding = con.getContentEncoding(); + encoding = encoding == null ? "UTF-8" : encoding; + String body = IOUtils.toString(in, encoding); + + JSONTokener tokener = new JSONTokener(body); + JSONObject jsonData = new JSONObject(tokener); + + return jsonData; + } + catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + public String getPropertyKey(String value, int offset) { + LocalRange range = getPropertyRange(value, offset); + if (range != null) { + return value.substring(range.getStart(), range.getEnd()); + } + return null; + } + + public LocalRange getPropertyRange(String value, int offset) { + int start = -1; + int end = -1; + + for (int i = offset - 1; i >= 0; i--) { + if (value.charAt(i) == '{') { + start = i + 1; + break; + } + else if (value.charAt(i) == '}') { + break; + } + } + + for(int i = offset; i < value.length(); i++) { + if (value.charAt(i) == '{' || value.charAt(i) == '$') { + break; + } + else if (value.charAt(i) == '}') { + end = i; + break; + } + } + + if (start > 0 && start < value.length() && end > 0 && end <= value.length() && start < end) { + return new LocalRange(start, end); + } + + return null; + } + + public static class LocalRange { + private int start; + private int end; + + public LocalRange(int start, int end) { + this.start = start; + this.end = end; + } + + public int getStart() { + return start; + } + + public int getEnd() { + return end; + } + + } + +} diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java new file mode 100644 index 000000000..2871fb420 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * 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.boot.metadata; + +import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.languageserver.ProgressService; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.util.FuzzyMap; +import org.springframework.ide.vscode.commons.util.text.IDocument; + +public class DefaultSpringPropertyIndexProvider implements SpringPropertyIndexProvider { + + private static final FuzzyMap EMPTY_INDEX = new SpringPropertyIndex(null); + + private JavaProjectFinder javaProjectFinder; + private SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(); + + private ProgressService progressService = (id, msg) -> { + /* ignore */ }; + + public DefaultSpringPropertyIndexProvider(JavaProjectFinder javaProjectFinder) { + this.javaProjectFinder = javaProjectFinder; + } + + @Override + public FuzzyMap getIndex(IDocument doc) { + IJavaProject jp = javaProjectFinder.find(doc); + if (jp != null) { + return indexManager.get(jp, progressService); + } + return EMPTY_INDEX; + } + + public void setProgressService(ProgressService progressService) { + this.progressService = progressService; + } + +} diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/PropertiesLoader.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/PropertiesLoader.java new file mode 100644 index 000000000..79779f133 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/PropertiesLoader.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * 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.boot.metadata; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.jar.JarFile; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; + +import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; +import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder; +import org.springframework.ide.vscode.commons.java.IClasspath; + +public class PropertiesLoader { + + private static final String MAIN_SPRING_CONFIGURATION_METADATA_JSON = "META-INF/spring-configuration-metadata.json"; + + public static final String ADDITIONAL_SPRING_CONFIGURATION_METADATA_JSON = "META-INF/additional-spring-configuration-metadata.json"; + + /** + * The default classpath location for config metadata loaded when scanning .jar files on the classpath. + */ + public static final String[] JAR_META_DATA_LOCATIONS = { + MAIN_SPRING_CONFIGURATION_METADATA_JSON + //Not scanning 'additional' metadata because it integrated already in the main data. + }; + + /** + * The default classpath location for config metadata loaded when scanning project output folders. + */ + public static final String[] PROJECT_META_DATA_LOCATIONS = { + MAIN_SPRING_CONFIGURATION_METADATA_JSON, + ADDITIONAL_SPRING_CONFIGURATION_METADATA_JSON + }; + + private static final Logger LOG = Logger.getLogger(PropertiesLoader.class.getName()); + + private ConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder.create(); + + public ConfigurationMetadataRepository load(IClasspath classPath) { + try { + classPath.getClasspathEntries().forEach(entry -> { + File fileEntry = entry.toFile(); + if (fileEntry.exists()) { + if (fileEntry.isDirectory()) { + loadFromOutputFolder(entry); + } else { + loadFromJar(entry); + } + } + }); + } catch (Exception e) { + LOG.log(Level.SEVERE, "Failed to retrieve classpath", e); + } + ConfigurationMetadataRepository repository = builder.build(); + return repository; + } + + private void loadFromOutputFolder(Path outputFolderPath) { + if (outputFolderPath != null && Files.exists(outputFolderPath)) { + Arrays.stream(PROJECT_META_DATA_LOCATIONS).forEach(mdLoc -> { + loadFromJsonFile(outputFolderPath.resolve(mdLoc)); + }); + } + } + + private void loadFromJsonFile(Path mdf) { + if (Files.exists(mdf)) { + InputStream is = null; + try { + is = Files.newInputStream(mdf); + loadFromInputStream(is); + } catch (Exception e) { + LOG.log(Level.SEVERE, "Error loading file '" + mdf + "'", e); + } finally { + if (is!=null) { + try { + is.close(); + } catch (IOException e) { + //ignore + } + } + } + } + } + + private void loadFromJar(Path f) { + JarFile jarFile = null; + try { + jarFile = new JarFile(f.toFile()); + //jarDump(jarFile); + for (String loc : JAR_META_DATA_LOCATIONS) { + ZipEntry e = jarFile.getEntry(loc); + if (e!=null) { + loadFrom(jarFile, e); + } + } + } catch (Throwable e) { + LOG.log(Level.SEVERE, "Error loading JAR file", e); + } finally { + if (jarFile!=null) { + try { + jarFile.close(); + } catch (IOException e) { + } + } + } + } + + + private void loadFrom(JarFile jarFile, ZipEntry ze) { + InputStream is = null; + try { + is = jarFile.getInputStream(ze); + loadFromInputStream(is); + } catch (Throwable e) { + LOG.log(Level.SEVERE, "Error loading JAR file", e); + } finally { + if (is!=null) { + try { + is.close(); + } catch (IOException e) { + } + } + } + } + + private void loadFromInputStream(InputStream is) throws IOException { + builder.withJsonResource(is); + } + +} diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java new file mode 100644 index 000000000..a7d3e6550 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2014, 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.boot.metadata; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.languageserver.ProgressService; +import org.springframework.ide.vscode.commons.util.FuzzyMap; + +/** + * Support for Reconciling, Content Assist and Hover Text in spring properties + * file all make use of a per-project index of spring properties metadata extracted + * from project's classpath. This Index manager is responsible for keeping at most + * one index per-project and to keep the index up-to-date. + * + * @author Kris De Volder + */ +public class SpringPropertiesIndexManager { + + private Map indexes = null; + private static int progressIdCt = 0; + + public SpringPropertiesIndexManager() { + } + + public synchronized FuzzyMap get(IJavaProject project, ProgressService progressService) { + if (indexes==null) { + indexes = new HashMap<>(); + } + + SpringPropertyIndex index = indexes.get(project); + if (index==null) { + String progressId = getProgressId(); + if (progressService != null) { + progressService.progressEvent(progressId, "Indexing Spring Boot Properties..."); + } + + index = new SpringPropertyIndex(project.getClasspath()); + indexes.put(project, index); + + if (progressService != null) { + progressService.progressEvent(progressId, null); + } + } + return index; + } + + private static synchronized String getProgressId() { + return DefaultSpringPropertyIndexProvider.class.getName()+ (progressIdCt++); + } + +} diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndex.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndex.java new file mode 100644 index 000000000..44a244d7e --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndex.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2015, 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.boot.metadata; + +import java.util.Collection; + +import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; +import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; +import org.springframework.ide.vscode.commons.java.IClasspath; +import org.springframework.ide.vscode.commons.util.FuzzyMap; + +public class SpringPropertyIndex extends FuzzyMap { + + public SpringPropertyIndex(IClasspath projectPath) { + if (projectPath!=null) { + PropertiesLoader loader = new PropertiesLoader(); + ConfigurationMetadataRepository metadata = loader.load(projectPath); + Collection allEntries = metadata.getAllProperties().values(); + for (ConfigurationMetadataProperty item : allEntries) { + add(item); + } + } + } + + /** + * Dumps out 'test data' based on the current contents of the index. This is not meant to be + * used in 'production' code. The idea is to call this method during development to dump a + * 'snapshot' of the index onto System.out. The data is printed in a forma so that it can be easily + * pasted/used into JUNit testing code. + */ +// public void dumpAsTestData() { +// List> allData = this.find(""); +// for (Match match : allData) { +// PropertyInfo d = match.data; +// System.out.println("data(" +// +dumpString(d.getId())+", " +// +dumpString(d.getType())+", " +// +dumpString(d.getDefaultValue())+", " +// +dumpString(d.getDescription()) +");" +// ); +// for (PropertySource source : d.getSources()) { +// String st = source.getSourceType(); +// String sm = source.getSourceMethod(); +// if (sm!=null) { +// System.out.println(d.getId() +" from: "+st+"::"+sm); +// } +// } +// } +// } + +// private String dumpString(Object v) { +// if (v==null) { +// return "null"; +// } +// return dumpString(""+v); +// } + + private String dumpString(String s) { + if (s==null) { + return "null"; + } else { + StringBuilder buf = new StringBuilder("\""); + for (char c : s.toCharArray()) { + switch (c) { + case '\r': + buf.append("\\r"); + break; + case '\n': + buf.append("\\n"); + break; + case '\\': + buf.append("\\\\"); + break; + case '\"': + buf.append("\\\""); + break; + default: + buf.append(c); + break; + } + } + buf.append("\""); + return buf.toString(); + } + } + + @Override + protected String getKey(ConfigurationMetadataProperty entry) { + return entry.getId(); + } + + /** + * Find the longest known property that is a prefix of the given name. Here prefix does not mean + * 'string prefix' but a prefix in the sense of treating '.' as a kind of separators. So + * 'prefix' is not allowed to end in the middle of a 'segment'. + */ +// public static PropertyInfo findLongestValidProperty(FuzzyMap index, String name) { +// int bracketPos = name.indexOf('['); +// int endPos = bracketPos>=0?bracketPos:name.length(); +// PropertyInfo prop = null; +// String prefix = null; +// while (endPos>0 && prop==null) { +// prefix = name.substring(0, endPos); +// String canonicalPrefix = StringUtil.camelCaseToHyphens(prefix); +// prop = index.get(canonicalPrefix); +// if (prop==null) { +// endPos = name.lastIndexOf('.', endPos-1); +// } +// } +// if (prop!=null) { +// //We should meet caller's expectation that matched properties returned by this method +// // match the names exactly even if we found them using relaxed name matching. +// return prop.withId(prefix); +// } +// return null; +// } + +} diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndexProvider.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndexProvider.java new file mode 100644 index 000000000..7bd2ee815 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndexProvider.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2015, 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.boot.metadata; + +import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; +import org.springframework.ide.vscode.commons.util.FuzzyMap; +import org.springframework.ide.vscode.commons.util.text.IDocument; + + +@FunctionalInterface +public interface SpringPropertyIndexProvider { + FuzzyMap getIndex(IDocument doc); +} diff --git a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/completions/test/ScopeCompletionTest.java b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/completions/test/ScopeCompletionTest.java index 02f21e878..696ae5547 100644 --- a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/completions/test/ScopeCompletionTest.java +++ b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/completions/test/ScopeCompletionTest.java @@ -27,6 +27,7 @@ import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFin import org.springframework.ide.vscode.languageserver.testharness.Editor; import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness; import org.springframework.ide.vscode.project.harness.ProjectsHarness; +import org.springframework.ide.vscode.project.harness.PropertyIndexHarness; /** * @author Martin Lippert @@ -36,18 +37,21 @@ public class ScopeCompletionTest { private final JavaProjectFinder javaProjectFinder = (doc) -> getTestProject(); private LanguageServerHarness harness; + private PropertyIndexHarness indexHarness; private IJavaProject testProject; private Editor editor; + @Before public void setup() throws Exception { - testProject = ProjectsHarness.INSTANCE.mavenProject("test-scope-annotation"); + testProject = ProjectsHarness.INSTANCE.mavenProject("test-annotations"); + indexHarness = new PropertyIndexHarness(); harness = new LanguageServerHarness(new Callable() { @Override public BootJavaLanguageServer call() throws Exception { - BootJavaLanguageServer server = new BootJavaLanguageServer(javaProjectFinder); + BootJavaLanguageServer server = new BootJavaLanguageServer(javaProjectFinder, indexHarness.getIndexProvider()); return server; } }) { @@ -155,7 +159,7 @@ public class ScopeCompletionTest { } private void prepareCase(String selectedAnnotation, String annotationStatementBeforeTest) throws Exception { - InputStream resource = this.getClass().getResourceAsStream("/test-projects/test-scope-annotation/src/main/java/org/test/TestScopeCompletion.java"); + InputStream resource = this.getClass().getResourceAsStream("/test-projects/test-annotations/src/main/java/org/test/TestScopeCompletion.java"); String content = IOUtils.toString(resource); content = content.replace(selectedAnnotation, annotationStatementBeforeTest); diff --git a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/completions/test/ValueCompletionTest.java b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/completions/test/ValueCompletionTest.java new file mode 100644 index 000000000..3a4e25eb2 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/completions/test/ValueCompletionTest.java @@ -0,0 +1,299 @@ +/******************************************************************************* + * 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.boot.java.completions.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.InputStream; +import java.util.List; +import java.util.concurrent.Callable; + +import org.apache.commons.io.IOUtils; +import org.eclipse.lsp4j.CompletionItem; +import org.junit.Before; +import org.junit.Test; +import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer; +import org.springframework.ide.vscode.boot.java.completions.ValueCompletionProcessor; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.languageserver.testharness.Editor; +import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness; +import org.springframework.ide.vscode.project.harness.ProjectsHarness; +import org.springframework.ide.vscode.project.harness.PropertyIndexHarness; + +/** + * @author Martin Lippert + */ +public class ValueCompletionTest { + + private final JavaProjectFinder javaProjectFinder = (doc) -> getTestProject(); + + private LanguageServerHarness harness; + private IJavaProject testProject; + + private Editor editor; + + private PropertyIndexHarness indexHarness; + + @Before + public void setup() throws Exception { + testProject = ProjectsHarness.INSTANCE.mavenProject("test-annotations"); + indexHarness = new PropertyIndexHarness(); + + harness = new LanguageServerHarness(new Callable() { + @Override + public BootJavaLanguageServer call() throws Exception { + BootJavaLanguageServer server = new BootJavaLanguageServer(javaProjectFinder, indexHarness.getIndexProvider()); + return server; + } + }) { + @Override + protected String getFileExtension() { + return ".java"; + } + }; + harness.intialize(null); + } + + private IJavaProject getTestProject() { + return testProject; + } + + @Test + public void testPrefixIdentification() { + ValueCompletionProcessor processor = new ValueCompletionProcessor(null); + + assertEquals("pre", processor.identifyPropertyPrefix("pre", 3)); + assertEquals("pre", processor.identifyPropertyPrefix("prefix", 3)); + assertEquals("", processor.identifyPropertyPrefix("", 0)); + assertEquals("pre", processor.identifyPropertyPrefix("$pre", 4)); + + assertEquals("", processor.identifyPropertyPrefix("${pre", 0)); + assertEquals("", processor.identifyPropertyPrefix("${pre", 1)); + assertEquals("", processor.identifyPropertyPrefix("${pre", 2)); + assertEquals("p", processor.identifyPropertyPrefix("${pre", 3)); + assertEquals("pr", processor.identifyPropertyPrefix("${pre", 4)); + } + + @Test + public void testEmptyBracketsCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(<*>)"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"${data.prop2}\"<*>)", + "@Value(\"${else.prop3}\"<*>)", + "@Value(\"${spring.prop1}\"<*>)"); + } + + @Test + public void testEmptyBracketsCompletionWithParamName() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(value=<*>)"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(value=\"${data.prop2}\"<*>)", + "@Value(value=\"${else.prop3}\"<*>)", + "@Value(value=\"${spring.prop1}\"<*>)"); + } + + @Test + public void testEmptyBracketsCompletionWithWrongParamName() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(another=<*>)"); + prepareDefaultIndexData(); + assertAnnotationCompletions(); + } + + @Test + public void testOnlyDollarNoQoutesCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value($<*>)"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"${data.prop2}\"<*>)", + "@Value(\"${else.prop3}\"<*>)", + "@Value(\"${spring.prop1}\"<*>)"); + } + + @Test + public void testOnlyDollarNoQoutesWithParamCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(value=$<*>)"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(value=\"${data.prop2}\"<*>)", + "@Value(value=\"${else.prop3}\"<*>)", + "@Value(value=\"${spring.prop1}\"<*>)"); + } + + @Test + public void testOnlyDollarCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(\"$<*>\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"${data.prop2}<*>\")", + "@Value(\"${else.prop3}<*>\")", + "@Value(\"${spring.prop1}<*>\")"); + } + + @Test + public void testOnlyDollarWithParamCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(value=\"$<*>\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(value=\"${data.prop2}<*>\")", + "@Value(value=\"${else.prop3}<*>\")", + "@Value(value=\"${spring.prop1}<*>\")"); + } + + @Test + public void testDollarWithBracketsCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(\"${<*>}\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"${data.prop2<*>}\")", + "@Value(\"${else.prop3<*>}\")", + "@Value(\"${spring.prop1<*>}\")"); + } + + @Test + public void testDollarWithBracketsWithParamCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(value=\"${<*>}\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(value=\"${data.prop2<*>}\")", + "@Value(value=\"${else.prop3<*>}\")", + "@Value(value=\"${spring.prop1<*>}\")"); + } + + @Test + public void testEmptyStringLiteralCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(\"<*>\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"${data.prop2}<*>\")", + "@Value(\"${else.prop3}<*>\")", + "@Value(\"${spring.prop1}<*>\")"); + } + + @Test + public void testPlainPrefixCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(spri<*>)"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"${spring.prop1}\"<*>)"); + } + + @Test + public void testQoutedPrefixCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(\"spri<*>\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"${spring.prop1}<*>\")"); + } + + @Test + public void testRandomSpelExpressionNoCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(\"#{<*>}\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"#{${data.prop2}<*>}\")", + "@Value(\"#{${else.prop3}<*>}\")", + "@Value(\"#{${spring.prop1}<*>}\")"); + } + + @Test + public void testRandomSpelExpressionWithPropertyDollar() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(\"#{345$<*>}\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"#{345${data.prop2}<*>}\")", + "@Value(\"#{345${else.prop3}<*>}\")", + "@Value(\"#{345${spring.prop1}<*>}\")"); + } + + @Test + public void testRandomSpelExpressionWithPropertyDollerWithoutClosindBracket() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(\"#{345${<*>}\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"#{345${data.prop2}<*>}\")", + "@Value(\"#{345${else.prop3}<*>}\")", + "@Value(\"#{345${spring.prop1}<*>}\")"); + } + + @Test + public void testRandomSpelExpressionWithPropertyDollerWithClosingBracket() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(\"#{345${<*>}}\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"#{345${data.prop2<*>}}\")", + "@Value(\"#{345${else.prop3<*>}}\")", + "@Value(\"#{345${spring.prop1<*>}}\")"); + } + + @Test + public void testRandomSpelExpressionWithPropertyPrefixWithoutClosingBracket() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(\"#{345${spri<*>}\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"#{345${spring.prop1}<*>}\")"); + } + + @Test + public void testRandomSpelExpressionWithPropertyPrefixWithClosingBracket() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(\"#{345${spri<*>}}\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(\"#{345${spring.prop1<*>}}\")"); + } + + private void prepareDefaultIndexData() { + indexHarness.data("spring.prop1", "java.lang.String", null, null); + indexHarness.data("data.prop2", "java.lang.String", null, null); + indexHarness.data("else.prop3", "java.lang.String", null, null); + } + + private void prepareCase(String selectedAnnotation, String annotationStatementBeforeTest) throws Exception { + InputStream resource = this.getClass().getResourceAsStream("/test-projects/test-annotations/src/main/java/org/test/TestValueCompletion.java"); + String content = IOUtils.toString(resource); + + content = content.replace(selectedAnnotation, annotationStatementBeforeTest); + editor = new Editor(harness, content, "java"); + } + + private void assertAnnotationCompletions(String... completedAnnotations) throws Exception { + List completions = editor.getCompletions(); + int i = 0; + for (String expectedCompleted : completedAnnotations) { + Editor clonedEditor = editor.clone(); + clonedEditor.apply(completions.get(i++)); + assertTrue(clonedEditor.getText().contains(expectedCompleted)); + } + + assertEquals(i, completions.size()); + } + +} diff --git a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/hover/test/ValueHoverTest.java b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/hover/test/ValueHoverTest.java new file mode 100644 index 000000000..63a3401a9 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/hover/test/ValueHoverTest.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.boot.java.hover.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; +import org.springframework.ide.vscode.boot.java.hover.ValueHoverProvider; + +/** + * @author Martin Lippert + */ +public class ValueHoverTest { + + @Test + public void testGetPropertyFromValue() { + ValueHoverProvider provider = new ValueHoverProvider(); + + assertNull(provider.getPropertyKey("${spring}", 0)); + assertNull(provider.getPropertyKey("${spring}", 1)); + assertEquals("spring", provider.getPropertyKey("${spring}", 2)); + assertEquals("spring", provider.getPropertyKey("${spring}", 3)); + assertEquals("spring", provider.getPropertyKey("${spring}", 8)); + assertNull(provider.getPropertyKey("${spring}", 9)); + + assertNull(provider.getPropertyKey("abc ${spring} and other stuff", 0)); + assertNull(provider.getPropertyKey("abc ${spring} and other stuff", 5)); + assertEquals("spring", provider.getPropertyKey("abc ${spring} and other stuff", 6)); + assertEquals("spring", provider.getPropertyKey("abc ${spring} and other stuff", 12)); + assertNull(provider.getPropertyKey("abc ${spring} and other stuff", 13)); + + assertNull(provider.getPropertyKey("abc ${spring} and ${boot} other stuff", 5)); + assertEquals("spring", provider.getPropertyKey("abc ${spring} and ${boot} other stuff", 6)); + assertEquals("spring", provider.getPropertyKey("abc ${spring} and ${boot} other stuff", 12)); + assertNull(provider.getPropertyKey("abc ${spring} and ${boot} other stuff", 13)); + + assertNull(provider.getPropertyKey("abc ${spring} and ${boot} other stuff", 19)); + assertEquals("boot", provider.getPropertyKey("abc ${spring} and ${boot} other stuff", 20)); + assertEquals("boot", provider.getPropertyKey("abc ${spring} and ${boot} other stuff", 24)); + assertNull(provider.getPropertyKey("abc ${spring} and ${boot} other stuff", 25)); + } + +} diff --git a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/project/harness/ProjectsHarness.java b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/project/harness/ProjectsHarness.java index 7f56c7744..516a0c3d4 100644 --- a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/project/harness/ProjectsHarness.java +++ b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/project/harness/ProjectsHarness.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 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 @@ -29,7 +29,6 @@ import com.google.common.cache.CacheBuilder; * Test projects harness * * @author Alex Boyko - * */ public class ProjectsHarness { @@ -51,7 +50,7 @@ public class ProjectsHarness { switch (type) { case MAVEN: MavenBuilder.newBuilder(testProjectPath).clean().pack().javadoc().skipTests().execute(); - return new MavenJavaProject(testProjectPath.resolve(MavenCore.POM_XML).toFile()); + return new MavenJavaProject(MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile()); case CLASSPATH_TXT: MavenBuilder.newBuilder(testProjectPath).clean().pack().skipTests().execute(); return new JavaProjectWithClasspathFile(testProjectPath.resolve(MavenCore.CLASSPATH_TXT).toFile()); @@ -62,94 +61,13 @@ public class ProjectsHarness { } protected Path getProjectPath(String name) throws URISyntaxException, IOException { -// URI sourceLocation = ProjectsHarness.class.getProtectionDomain().getCodeSource().getLocation().toURI(); -// // file:/Users/aboyko/git/sts4/vscode-extensions/commons/project-test-harness/target/project-test-harness-0.0.1-SNAPSHOT.jar -// Path testProjectsPath = Paths.get(sourceLocation).getParent().getParent().resolve("test-projects").resolve(name); -// if (Files.exists(testProjectsPath)) { -// return testProjectsPath; -// } else { -// /* -// * If "test-projects" folder is not found then extract test project -// * from the jar's "test-projects" folder and copy it in the temp -// * folder -// */ - return getProjectPathFromClasspath(name); -// } + return getProjectPathFromClasspath(name); } private Path getProjectPathFromClasspath(String name) throws URISyntaxException, IOException { URI resource = ProjectsHarness.class.getResource("/test-projects/" + name).toURI(); -// if (resource.getScheme().equalsIgnoreCase("jar")) { -// return getProjectPathFromJar(resource); -// } else { - return Paths.get(resource); -// } - } - -// private Path getProjectPathFromJar(URI jar) throws IOException { -// final String[] array = jar.toString().split("!"); -// URI firstHalf = URI.create(array[0]); -// Path tempFolderPath = Paths.get(new File(System.getProperty(MavenCore.JAVA_IO_TMPDIR)).toURI()); -// FileSystem fs = FileSystems.newFileSystem(firstHalf, Collections.emptyMap()); -// try { -// Path path = fs.getPath(array[1]); -// Path projectCopyPath = tempFolderPath.resolve(path.getFileName().toString()); -// if (Files.exists(projectCopyPath)) { -// recursiveDelete(projectCopyPath); -// } -// recursiveCopy(path, tempFolderPath, StandardCopyOption.REPLACE_EXISTING); -// System.out.println("Copied test project to: " + projectCopyPath); -// return projectCopyPath; -// } finally { -// fs.close(); -// } -// } -// -// private static void recursiveCopy(Path source, Path target, CopyOption... options) throws IOException { -// Files.walkFileTree(source, new SimpleFileVisitor() { -// -// Path destination = target; -// -// @Override -// public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { -// destination = destination.resolve(dir.getFileName().toString()); -// Files.copy(dir, destination, options); -// return super.preVisitDirectory(dir, attrs); -// } -// -// @Override -// public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { -// Path newFile = destination.resolve(file.getFileName().toString()); -// Files.copy(file, newFile, options); -// return super.visitFile(file, attrs); -// } -// -// @Override -// public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { -// destination = destination.getParent(); -// return super.postVisitDirectory(dir, exc); -// } -// -// }); -// } -// -// private static void recursiveDelete(Path path) throws IOException { -// Files.walkFileTree(path, new SimpleFileVisitor() { -// -// @Override -// public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { -// Files.delete(file); -// return super.visitFile(file, attrs); -// } -// -// @Override -// public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { -// Files.delete(dir); -// return super.postVisitDirectory(dir, exc); -// } -// -// }); -// } + return Paths.get(resource); + } public MavenJavaProject mavenProject(String name) throws Exception { return (MavenJavaProject) project(ProjectType.MAVEN, name); diff --git a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/project/harness/PropertyIndexHarness.java b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/project/harness/PropertyIndexHarness.java new file mode 100644 index 000000000..0295f438c --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/project/harness/PropertyIndexHarness.java @@ -0,0 +1,562 @@ +/******************************************************************************* + * 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.project.harness; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; +import org.springframework.boot.configurationmetadata.Deprecation; +import org.springframework.boot.configurationmetadata.ValueHint; +import org.springframework.boot.configurationmetadata.ValueProvider; +import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndex; +import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; +import org.springframework.ide.vscode.commons.java.IClasspath; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.util.FuzzyMap; +import org.springframework.ide.vscode.commons.util.text.IDocument; + +/** + * Provides some convenience apis for test code to create / use test data for a SpringPropertyIndex. + */ +public class PropertyIndexHarness { + + private Map datas = new LinkedHashMap<>(); + private SpringPropertyIndex index = null; + private IJavaProject testProject = null; + + protected final SpringPropertyIndexProvider indexProvider = new SpringPropertyIndexProvider() { + @Override + public FuzzyMap getIndex(IDocument doc) { + synchronized (PropertyIndexHarness.this) { + if (index==null) { + IClasspath classpath = testProject == null ? null : testProject.getClasspath(); + index = new SpringPropertyIndex(classpath); + for (ConfigurationMetadataProperty propertyInfo : datas.values()) { + index.add(propertyInfo); + } + } + return index; + } + } + }; + + public synchronized void useProject(IJavaProject p) throws Exception { + index = null; + this.testProject = p; + } + + public class ItemConfigurer { + + private ConfigurationMetadataProperty item; + + public ItemConfigurer(ConfigurationMetadataProperty item) { + this.item = item; + } + + /** + * Add a provider with a single parameter. + * @return + */ + public ItemConfigurer provider(String name, String paramName, Object paramValue) { + ValueProvider provider = new ValueProvider(); + provider.setName(name); + provider.getParameters().put(paramName, paramValue); + item.getHints().getValueProviders().add(provider); + return this; + } + + /** + * Add a value hint. If description contains a '.' the dot is used + * to break description into a short and long description. + * @return + */ + public ItemConfigurer valueHint(Object value, String description) { + ValueHint hint = new ValueHint(); + hint.setValue(value); + if (description!=null) { + int dotPos = description.indexOf('.'); + if (dotPos>=0) { + hint.setShortDescription( description.substring(0, dotPos)); + } + hint.setDescription(description); + } + item.getHints().getValueHints().add(hint); + return this; + } + } + + + public synchronized ItemConfigurer data(String id, String type, Object deflt, String description, + String... source + ) { + ConfigurationMetadataProperty item = new ConfigurationMetadataProperty(); + item.setId(id); + item.setDescription(description); + item.setType(type); + item.setDefaultValue(deflt); + index = null; + datas.put(item.getId(), item); + return new ItemConfigurer(item); + } + + public synchronized void keyHints(String id, String... hintValues) { + index = null; + List hints = datas.get(id).getHints().getKeyHints(); + for (String value : hintValues) { + ValueHint hint = new ValueHint(); + hint.setValue(value); + hints.add(hint); + } + } + + public synchronized void valueHints(String id, String... hintValues) { + index = null; + List hints = datas.get(id).getHints().getValueHints(); + for (String value : hintValues) { + ValueHint hint = new ValueHint(); + hint.setValue(value); + hints.add(hint); + } + } + + public synchronized void deprecate(String key, String replacedBy, String reason) { + index = null; + ConfigurationMetadataProperty info = datas.get(key); + Deprecation d = new Deprecation(); + d.setReplacement(replacedBy); + d.setReason(reason); + info.setDeprecation(d); + } + + /** + * Call this method to add some default test data to the Completion engine's index. + * Note that this data is not added automatically, some test may want to use smaller + * test data sets. + */ + public void defaultTestData() { + data("banner.charset", "java.nio.charset.Charset", "UTF-8", "Banner file encoding."); + data("banner.location", "java.lang.String", "classpath:banner.txt", "Banner file location."); + data("debug", "java.lang.Boolean", "false", "Enable debug logs."); + data("flyway.check-location", "java.lang.Boolean", "false", "Check that migration scripts location exists."); + data("flyway.clean-on-validation-error", "java.lang.Boolean", null, null); + data("flyway.enabled", "java.lang.Boolean", "true", "Enable flyway."); + data("flyway.encoding", "java.lang.String", null, null); + data("flyway.ignore-failed-future-migration", "java.lang.Boolean", null, null); + data("flyway.init-description", "java.lang.String", null, null); + data("flyway.init-on-migrate", "java.lang.Boolean", null, null); + data("flyway.init-sqls", "java.util.List", null, "SQL statements to execute to initialize a connection immediately after obtaining\n it."); + data("flyway.init-version", "org.flywaydb.core.api.MigrationVersion", null, null); + data("flyway.locations", "java.util.List", null, "Locations of migrations scripts."); + data("flyway.out-of-order", "java.lang.Boolean", null, null); + data("flyway.password", "java.lang.String", null, "Login password of the database to migrate."); + data("flyway.placeholder-prefix", "java.lang.String", null, null); + data("flyway.placeholders", "java.util.Map", null, null); + data("flyway.placeholder-suffix", "java.lang.String", null, null); + data("flyway.schemas", "java.lang.String[]", null, null); + data("flyway.sql-migration-prefix", "java.lang.String", null, null); + data("flyway.sql-migration-separator", "java.lang.String", null, null); + data("flyway.sql-migration-suffix", "java.lang.String", null, null); + data("flyway.table", "java.lang.String", null, null); + data("flyway.target", "org.flywaydb.core.api.MigrationVersion", null, null); + data("flyway.url", "java.lang.String", null, "JDBC url of the database to migrate. If not set, the primary configured data source\n is used."); + data("flyway.user", "java.lang.String", null, "Login user of the database to migrate."); + data("flyway.validate-on-migrate", "java.lang.Boolean", null, null); + data("http.mappers.json-pretty-print", "java.lang.Boolean", null, "Enable json pretty print."); + data("http.mappers.json-sort-keys", "java.lang.Boolean", null, "Enable key sorting."); + data("liquibase.change-log", "java.lang.String", "classpath:/db/changelog/db.changelog-master.yaml", "Change log configuration path."); + data("liquibase.check-change-log-location", "java.lang.Boolean", "true", "Check the change log location exists."); + data("liquibase.contexts", "java.lang.String", null, "Comma-separated list of runtime contexts to use."); + data("liquibase.default-schema", "java.lang.String", null, "Default database schema."); + data("liquibase.drop-first", "java.lang.Boolean", "false", "Drop the database schema first."); + data("liquibase.enabled", "java.lang.Boolean", "true", "Enable liquibase support."); + data("liquibase.password", "java.lang.String", null, "Login password of the database to migrate."); + data("liquibase.url", "java.lang.String", null, "JDBC url of the database to migrate. If not set, the primary configured data source\n is used."); + data("liquibase.user", "java.lang.String", null, "Login user of the database to migrate."); + data("logging.config", "java.lang.String", null, "Location of the logging configuration file."); + data("logging.file", "java.lang.String", null, "Log file name."); + data("logging.level", "java.util.Map", null, "Log levels severity mapping. Use 'root' for the root logger."); + data("logging.path", "java.lang.String", null, "Location of the log file."); + data("multipart.file-size-threshold", "java.lang.String", "0", "Threshold after which files will be written to disk. Values can use the suffixed\n \"MB\" or \"KB\" to indicate a Megabyte or Kilobyte size."); + data("multipart.location", "java.lang.String", null, "Intermediate location of uploaded files."); + data("multipart.max-file-size", "java.lang.String", "1Mb", "Max file size. Values can use the suffixed \"MB\" or \"KB\" to indicate a Megabyte or\n Kilobyte size."); + data("multipart.max-request-size", "java.lang.String", "10Mb", "Max request size. Values can use the suffixed \"MB\" or \"KB\" to indicate a Megabyte\n or Kilobyte size."); + data("security.basic.enabled", "java.lang.Boolean", "true", "Enable basic authentication."); + data("security.basic.path", "java.lang.String[]", "[Ljava.lang.Object;@7abd0056", "Comma-separated list of paths to secure."); + data("security.basic.realm", "java.lang.String", "Spring", "HTTP basic realm name."); + data("security.enable-csrf", "java.lang.Boolean", "false", "Enable Cross Site Request Forgery support."); + data("security.filter-order", "java.lang.Integer", "0", "Security filter chain order."); + data("security.headers.cache", "java.lang.Boolean", "false", "Enable cache control HTTP headers."); + data("security.headers.content-type", "java.lang.Boolean", "false", "Enable \"X-Content-Type-Options\" header."); + data("security.headers.frame", "java.lang.Boolean", "false", "Enable \"X-Frame-Options\" header."); + data("security.headers.hsts", "org.springframework.boot.autoconfigure.security.SecurityProperties$Headers$HSTS", null, "HTTP Strict Transport Security (HSTS) mode (none, domain, all)."); + data("security.headers.xss", "java.lang.Boolean", "false", "Enable cross site scripting (XSS) protection."); + data("security.ignored", "java.util.List", null, "Comma-separated list of paths to exclude from the default secured paths."); + data("security.require-ssl", "java.lang.Boolean", "false", "Enable secure channel for all requests."); + data("security.sessions", "org.springframework.security.config.http.SessionCreationPolicy", null, "Session creation policy (always, never, if_required, stateless)."); + data("security.user.name", "java.lang.String", "user", "Default user name."); + data("security.user.password", "java.lang.String", null, "Password for the default user name."); + data("security.user.role", "java.util.List", null, "Granted roles for the default user name."); + data("server.address", "java.net.InetAddress", null, "Network address to which the server should bind to."); + data("server.context-parameters", "java.util.Map", null, "ServletContext parameters."); + data("server.context-path", "java.lang.String", null, "Context path of the application."); + data("server.port", "java.lang.Integer", null, "Server HTTP port."); + data("server.servlet-path", "java.lang.String", "/", "Path of the main dispatcher servlet."); + data("server.session-timeout", "java.lang.Integer", null, "Session timeout in seconds."); + data("server.ssl.ciphers", "java.lang.String[]", null, null); + data("server.ssl.client-auth", "org.springframework.boot.context.embedded.Ssl$ClientAuth", null, null); + data("server.ssl.key-alias", "java.lang.String", null, null); + data("server.ssl.key-password", "java.lang.String", null, null); + data("server.ssl.key-store", "java.lang.String", null, null); + data("server.ssl.key-store-password", "java.lang.String", null, null); + data("server.ssl.key-store-provider", "java.lang.String", null, null); + data("server.ssl.key-store-type", "java.lang.String", null, null); + data("server.ssl.protocol", "java.lang.String", null, null); + data("server.ssl.trust-store", "java.lang.String", null, null); + data("server.ssl.trust-store-password", "java.lang.String", null, null); + data("server.ssl.trust-store-provider", "java.lang.String", null, null); + data("server.ssl.trust-store-type", "java.lang.String", null, null); + data("server.tomcat.access-log-enabled", "java.lang.Boolean", "false", "Enable access log."); + data("server.tomcat.access-log-pattern", "java.lang.String", null, "Format pattern for access logs."); + data("server.tomcat.background-processor-delay", "java.lang.Integer", "30", "Delay in seconds between the invocation of backgroundProcess methods."); + data("server.tomcat.basedir", "java.io.File", null, "Tomcat base directory. If not specified a temporary directory will be used."); + data("server.tomcat.internal-proxies", "java.lang.String", "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|192\\.168\\.\\d{1,3}\\.\\d{1,3}|169\\.254\\.\\d{1,3}\\.\\d{1,3}|127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}", "Regular expression that matches proxies that are to be trusted."); + data("server.tomcat.max-http-header-size", "java.lang.Integer", "0", "Maximum size in bytes of the HTTP message header."); + data("server.tomcat.max-threads", "java.lang.Integer", "0", "Maximum amount of worker threads."); + data("server.tomcat.port-header", "java.lang.String", null, "Name of the HTTP header used to override the original port value."); + data("server.tomcat.protocol-header", "java.lang.String", null, "Header that holds the incoming protocol, usually named \"X-Forwarded-Proto\".\n Configured as a RemoteIpValve only if remoteIpHeader is also set."); + data("server.tomcat.remote-ip-header", "java.lang.String", null, "Name of the http header from which the remote ip is extracted. Configured as a\n RemoteIpValve only if remoteIpHeader is also set."); + data("server.tomcat.uri-encoding", "java.lang.String", null, "Character encoding to use to decode the URI."); + data("server.undertow.buffer-size", "java.lang.Integer", null, "Size of each buffer in bytes."); + data("server.undertow.buffers-per-region", "java.lang.Integer", null, "Number of buffer per region."); + data("server.undertow.direct-buffers", "java.lang.Boolean", null, null); + data("server.undertow.io-threads", "java.lang.Integer", null, "Number of I/O threads to create for the worker."); + data("server.undertow.worker-threads", "java.lang.Integer", null, "Number of worker threads."); + data("spring.activemq.broker-url", "java.lang.String", null, "URL of the ActiveMQ broker. Auto-generated by default."); + data("spring.activemq.in-memory", "java.lang.Boolean", "true", "Specify if the default broker URL should be in memory. Ignored if an explicit\n broker has been specified."); + data("spring.activemq.password", "java.lang.String", null, "Login password of the broker."); + data("spring.activemq.pooled", "java.lang.Boolean", "false", "Specify if a PooledConnectionFactory should be created instead of a regular\n ConnectionFactory."); + data("spring.activemq.user", "java.lang.String", null, "Login user of the broker."); + data("spring.aop.auto", "java.lang.Boolean", "true", "Add @EnableAspectJAutoProxy."); + data("spring.aop.proxy-target-class", "java.lang.Boolean", "false", "Whether subclass-based (CGLIB) proxies are to be created (true) as opposed to standard Java interface-based proxies (false)."); + data("spring.application.index", "java.lang.Integer", null, "Application index."); + data("spring.application.name", "java.lang.String", null, "Application name."); + data("spring.batch.initializer.enabled", "java.lang.Boolean", "true", "Create the required batch tables on startup if necessary."); + data("spring.batch.job.enabled", "java.lang.Boolean", "true", "Execute all Spring Batch jobs in the context on startup."); + data("spring.batch.job.names", "java.lang.String", "", "Comma-separated list of job names to execute on startup. By default, all Jobs\n found in the context are executed."); + data("spring.batch.schema", "java.lang.String", "classpath:org/springframework/batch/core/schema-@@platform@@.sql", "Path to the SQL file to use to initialize the database schema."); + data("spring.config.location", "java.lang.String", null, "Config file locations."); + data("spring.config.name", "java.lang.String", "application", "Config file name."); + data("spring.dao.exceptiontranslation.enabled", "java.lang.Boolean", "true", "Enable the PersistenceExceptionTranslationPostProcessor."); + data("spring.data.elasticsearch.cluster-name", "java.lang.String", "elasticsearch", "Elasticsearch cluster name."); + data("spring.data.elasticsearch.cluster-nodes", "java.lang.String", null, "Comma-separated list of cluster node addresses. If not specified, starts a client\n node."); + data("spring.data.elasticsearch.repositories.enabled", "java.lang.Boolean", "true", "Enable Elasticsearch repositories."); + data("spring.data.jpa.repositories.enabled", "java.lang.Boolean", "true", "Enable JPA repositories."); + data("spring.data.mongodb.authentication-database", "java.lang.String", null, "Authentication database name."); + data("spring.data.mongodb.database", "java.lang.String", null, "Database name."); + data("spring.data.mongodb.grid-fs-database", "java.lang.String", null, "GridFS database name."); + data("spring.data.mongodb.host", "java.lang.String", null, "Mongo server host."); + data("spring.data.mongodb.password", "char[]", null, "Login password of the mongo server."); + data("spring.data.mongodb.port", "java.lang.Integer", null, "Mongo server port."); + data("spring.data.mongodb.repositories.enabled", "java.lang.Boolean", "true", "Enable Mongo repositories."); + data("spring.data.mongodb.uri", "java.lang.String", "mongodb://localhost/test", "Mmongo database URI. When set, host and port are ignored."); + data("spring.data.mongodb.username", "java.lang.String", null, "Login user of the mongo server."); + data("spring.data.rest.base-uri", "java.net.URI", null, null); + data("spring.data.rest.default-page-size", "java.lang.Integer", null, null); + data("spring.data.rest.limit-param-name", "java.lang.String", null, null); + data("spring.data.rest.max-page-size", "java.lang.Integer", null, null); + data("spring.data.rest.page-param-name", "java.lang.String", null, null); + data("spring.data.rest.return-body-on-create", "java.lang.Boolean", null, null); + data("spring.data.rest.return-body-on-update", "java.lang.Boolean", null, null); + data("spring.data.rest.sort-param-name", "java.lang.String", null, null); + data("spring.data.solr.host", "java.lang.String", "http://127.0.0.1:8983/solr", "Solr host. Ignored if \"zk-host\" is set."); + data("spring.data.solr.repositories.enabled", "java.lang.Boolean", "true", "Enable Solr repositories."); + data("spring.data.solr.zk-host", "java.lang.String", null, "ZooKeeper host address in the form HOST:PORT."); + data("spring.datasource.abandon-when-percentage-full", "java.lang.Integer", null, null); + data("spring.datasource.access-to-underlying-connection-allowed", "java.lang.Boolean", null, null); + data("spring.datasource.alternate-username-allowed", "java.lang.Boolean", null, null); + data("spring.datasource.auto-commit", "java.lang.Boolean", null, null); + data("spring.datasource.catalog", "java.lang.String", null, null); + data("spring.datasource.commit-on-return", "java.lang.Boolean", null, null); + data("spring.datasource.connection-customizer-class-name", "java.lang.String", null, null); + data("spring.datasource.connection-init-sql", "java.lang.String", null, null); + data("spring.datasource.connection-init-sqls", "java.util.Collection", null, null); + data("spring.datasource.connection-properties", "java.lang.String", null, null); + data("spring.datasource.connection-test-query", "java.lang.String", null, null); + data("spring.datasource.connection-timeout", "java.lang.Long", null, null); + data("spring.datasource.continue-on-error", "java.lang.Boolean", "false", "Do not stop if an error occurs while initializing the database."); + data("spring.datasource.data", "java.lang.String", null, "Data (DML) script resource reference."); + data("spring.datasource.data-source-class-name", "java.lang.String", null, null); + data("spring.datasource.data-source", "java.lang.Object", null, null); + data("spring.datasource.data-source-j-n-d-i", "java.lang.String", null, null); + data("spring.datasource.data-source-properties", "java.util.Properties", null, null); + data("spring.datasource.db-properties", "java.util.Properties", null, null); + data("spring.datasource.default-auto-commit", "java.lang.Boolean", null, null); + data("spring.datasource.default-catalog", "java.lang.String", null, null); + data("spring.datasource.default-read-only", "java.lang.Boolean", null, null); + data("spring.datasource.default-transaction-isolation", "java.lang.Integer", null, null); + data("spring.datasource.driver-class-name", "java.lang.String", null, "Fully qualified name of the JDBC driver. Auto-detected based on the URL by default."); + data("spring.datasource.fair-queue", "java.lang.Boolean", null, null); + data("spring.datasource.idle-timeout", "java.lang.Long", null, null); + data("spring.datasource.ignore-exception-on-pre-load", "java.lang.Boolean", null, null); + data("spring.datasource.initialization-fail-fast", "java.lang.Boolean", null, null); + data("spring.datasource.initialize", "java.lang.Boolean", "true", "Populate the database using 'data.sql'."); + data("spring.datasource.initial-size", "java.lang.Integer", null, null); + data("spring.datasource.init-s-q-l", "java.lang.String", null, null); + data("spring.datasource.isolate-internal-queries", "java.lang.Boolean", null, null); + data("spring.datasource.jdbc4-connection-test", "java.lang.Boolean", null, null); + data("spring.datasource.jdbc-interceptors", "java.lang.String", null, null); + data("spring.datasource.jdbc-url", "java.lang.String", null, null); + data("spring.datasource.jmx-enabled", "java.lang.Boolean", "false", "Enable JMX support (if provided by the underlying pool)."); + data("spring.datasource.jndi-name", "java.lang.String", null, "JNDI location of the datasource. Class, url, username & password are ignored when\n set."); + data("spring.datasource.leak-detection-threshold", "java.lang.Long", null, null); + data("spring.datasource.log-abandoned", "java.lang.Boolean", null, null); + data("spring.datasource.login-timeout", "java.lang.Integer", null, null); + data("spring.datasource.log-validation-errors", "java.lang.Boolean", null, null); + data("spring.datasource.max-active", "java.lang.Integer", null, null); + data("spring.datasource.max-age", "java.lang.Long", null, null); + data("spring.datasource.max-idle", "java.lang.Integer", null, null); + data("spring.datasource.maximum-pool-size", "java.lang.Integer", null, null); + data("spring.datasource.max-lifetime", "java.lang.Long", null, null); + data("spring.datasource.max-open-prepared-statements", "java.lang.Integer", null, null); + data("spring.datasource.max-wait", "java.lang.Integer", null, null); + data("spring.datasource.metric-registry", "java.lang.Object", null, null); + data("spring.datasource.min-evictable-idle-time-millis", "java.lang.Integer", null, null); + data("spring.datasource.min-idle", "java.lang.Integer", null, null); + data("spring.datasource.minimum-idle", "java.lang.Integer", null, null); + data("spring.datasource.name", "java.lang.String", null, null); + data("spring.datasource.num-tests-per-eviction-run", "java.lang.Integer", null, null); + data("spring.datasource.password", "java.lang.String", null, "Login password of the database."); + data("spring.datasource.platform", "java.lang.String", "all", "Platform to use in the schema resource (schema-${platform}.sql)."); + data("spring.datasource.pool-name", "java.lang.String", null, null); + data("spring.datasource.pool-prepared-statements", "java.lang.Boolean", null, null); + data("spring.datasource.propagate-interrupt-state", "java.lang.Boolean", null, null); + data("spring.datasource.read-only", "java.lang.Boolean", null, null); + data("spring.datasource.register-mbeans", "java.lang.Boolean", null, null); + data("spring.datasource.remove-abandoned", "java.lang.Boolean", null, null); + data("spring.datasource.remove-abandoned-timeout", "java.lang.Integer", null, null); + data("spring.datasource.rollback-on-return", "java.lang.Boolean", null, null); + data("spring.datasource.schema", "java.lang.String", null, "Schema (DDL) script resource reference."); + data("spring.datasource.separator", "java.lang.String", ";", "Statement separator in SQL initialization scripts."); + data("spring.datasource.sql-script-encoding", "java.lang.String", null, "SQL scripts encoding."); + data("spring.datasource.suspect-timeout", "java.lang.Integer", null, null); + data("spring.datasource.test-on-borrow", "java.lang.Boolean", null, null); + data("spring.datasource.test-on-connect", "java.lang.Boolean", null, null); + data("spring.datasource.test-on-return", "java.lang.Boolean", null, null); + data("spring.datasource.test-while-idle", "java.lang.Boolean", null, null); + data("spring.datasource.time-between-eviction-runs-millis", "java.lang.Integer", null, null); + data("spring.datasource.transaction-isolation", "java.lang.String", null, null); + data("spring.datasource.url", "java.lang.String", null, "JDBC url of the database."); + data("spring.datasource.use-disposable-connection-facade", "java.lang.Boolean", null, null); + data("spring.datasource.use-equals", "java.lang.Boolean", null, null); + data("spring.datasource.use-lock", "java.lang.Boolean", null, null); + data("spring.datasource.username", "java.lang.String", null, "Login user of the database."); + data("spring.datasource.validation-interval", "java.lang.Long", null, null); + data("spring.datasource.validation-query", "java.lang.String", null, null); + data("spring.datasource.validation-query-timeout", "java.lang.Integer", null, null); + data("spring.datasource.validator-class-name", "java.lang.String", null, null); + data("spring.datasource.xa.data-source-class-name", "java.lang.String", null, "XA datasource fully qualified name."); + data("spring.datasource.xa.properties", "java.util.Map", null, "Properties to pass to the XA data source."); + data("spring.freemarker.allow-request-override", "java.lang.Boolean", null, "Set whether HttpServletRequest attributes are allowed to override (hide) controller\n generated model attributes of the same name."); + data("spring.freemarker.cache", "java.lang.Boolean", null, "Enable template caching."); + data("spring.freemarker.char-set", "java.lang.String", null, null); + data("spring.freemarker.charset", "java.lang.String", null, "Template encoding."); + data("spring.freemarker.check-template-location", "java.lang.Boolean", null, "Check that the templates location exists."); + data("spring.freemarker.content-type", "java.lang.String", null, "Content-Type value."); + data("spring.freemarker.enabled", "java.lang.Boolean", null, "Enable MVC view resolution for this technology."); + data("spring.freemarker.expose-request-attributes", "java.lang.Boolean", null, "Set whether all request attributes should be added to the model prior to merging\n with the template."); + data("spring.freemarker.expose-session-attributes", "java.lang.Boolean", null, "Set whether all HttpSession attributes should be added to the model prior to\n merging with the template."); + data("spring.freemarker.expose-spring-macro-helpers", "java.lang.Boolean", null, "Set whether to expose a RequestContext for use by Spring's macro library, under the\n name \"springMacroRequestContext\"."); + data("spring.freemarker.prefix", "java.lang.String", null, "Prefix that gets prepended to view names when building a URL."); + data("spring.freemarker.request-context-attribute", "java.lang.String", null, "Name of the RequestContext attribute for all views."); + data("spring.freemarker.settings", "java.util.Map", null, "Well-known FreeMarker keys which will be passed to FreeMarker's Configuration."); + data("spring.freemarker.suffix", "java.lang.String", null, "Suffix that gets appended to view names when building a URL."); + data("spring.freemarker.template-loader-path", "java.lang.String[]", new String[] {"snuzzle" ,"buggles"}, "Comma-separated list of template paths."); + data("spring.freemarker.view-names", "java.lang.String[]", null, "White list of view names that can be resolved."); + data("spring.groovy.template.cache", "java.lang.Boolean", null, "Enable template caching."); + data("spring.groovy.template.char-set", "java.lang.String", null, null); + data("spring.groovy.template.charset", "java.lang.String", null, "Template encoding."); + data("spring.groovy.template.check-template-location", "java.lang.Boolean", null, "Check that the templates location exists."); + data("spring.groovy.template.configuration.auto-escape", "java.lang.Boolean", null, null); + data("spring.groovy.template.configuration.auto-indent", "java.lang.Boolean", null, null); + data("spring.groovy.template.configuration.auto-indent-string", "java.lang.String", null, null); + data("spring.groovy.template.configuration.auto-new-line", "java.lang.Boolean", null, null); + data("spring.groovy.template.configuration.base-template-class", "java.lang.Class", null, null); + data("spring.groovy.template.configuration.cache-templates", "java.lang.Boolean", null, null); + data("spring.groovy.template.configuration.declaration-encoding", "java.lang.String", null, null); + data("spring.groovy.template.configuration.expand-empty-elements", "java.lang.Boolean", null, null); + data("spring.groovy.template.configuration", "java.util.Map", null, "Configuration to pass to TemplateConfiguration."); + data("spring.groovy.template.configuration.locale", "java.util.Locale", null, null); + data("spring.groovy.template.configuration.new-line-string", "java.lang.String", null, null); + data("spring.groovy.template.configuration.resource-loader-path", "java.lang.String", null, null); + data("spring.groovy.template.configuration.use-double-quotes", "java.lang.Boolean", null, null); + data("spring.groovy.template.content-type", "java.lang.String", null, "Content-Type value."); + data("spring.groovy.template.enabled", "java.lang.Boolean", null, "Enable MVC view resolution for this technology."); + data("spring.groovy.template.prefix", "java.lang.String", "classpath:/templates/", "Prefix that gets prepended to view names when building a URL."); + data("spring.groovy.template.suffix", "java.lang.String", ".tpl", "Suffix that gets appended to view names when building a URL."); + data("spring.groovy.template.view-names", "java.lang.String[]", null, "White list of view names that can be resolved."); + data("spring.hornetq.embedded.cluster-password", "java.lang.String", null, "Cluster password. Randomly generated on startup by default"); + data("spring.hornetq.embedded.data-directory", "java.lang.String", null, "Journal file directory. Not necessary if persistence is turned off."); + data("spring.hornetq.embedded.enabled", "java.lang.Boolean", "true", "Enable embedded mode if the HornetQ server APIs are available."); + data("spring.hornetq.embedded.persistent", "java.lang.Boolean", "false", "Enable persistent store."); + data("spring.hornetq.embedded.queues", "java.lang.String[]", "[Ljava.lang.Object;@2f5ce114", "Comma-separate list of queues to create on startup."); + data("spring.hornetq.embedded.server-id", "java.lang.Integer", "0", "Server id. By default, an auto-incremented counter is used."); + data("spring.hornetq.embedded.topics", "java.lang.String[]", "[Ljava.lang.Object;@6272137a", "Comma-separate list of topics to create on startup."); + data("spring.hornetq.host", "java.lang.String", "localhost", "HornetQ broker host."); + data("spring.hornetq.mode", "org.springframework.boot.autoconfigure.jms.hornetq.HornetQMode", null, "HornetQ deployment mode, auto-detected by default. Can be explicitly set to\n \"native\" or \"embedded\"."); + data("spring.hornetq.port", "java.lang.Integer", "5445", "HornetQ broker port."); + data("spring.http.encoding.charset", "java.nio.charset.Charset", null, "Charset of HTTP requests and responses. Added to the \"Content-Type\" header if not\n set explicitly."); + data("spring.http.encoding.enabled", "java.lang.Boolean", "true", "Enable http encoding support."); + data("spring.http.encoding.force", "java.lang.Boolean", "true", "Force the encoding to the configured charset on HTTP requests and responses."); + data("spring.jackson.date-format", "java.lang.String", null, "Date format string (yyyy-MM-dd HH:mm:ss), or a fully-qualified date format class\n name."); + data("spring.jackson.deserialization", "java.util.Map", null, "Jackson on/off features that affect the way Java objects are deserialized."); + data("spring.jackson.generator", "java.util.Map", null, "Jackson on/off features for generators."); + data("spring.jackson.mapper", "java.util.Map", null, "Jackson general purpose on/off features."); + data("spring.jackson.parser", "java.util.Map", null, "Jackson on/off features for parsers."); + data("spring.jackson.property-naming-strategy", "java.lang.String", null, "One of the constants on Jackson's PropertyNamingStrategy\n (CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES). Can also be a fully-qualified class\n name of a PropertyNamingStrategy subclass."); + data("spring.jackson.serialization", "java.util.Map", null, "Jackson on/off features that affect the way Java objects are serialized."); + data("spring.jersey.filter.order", "java.lang.Integer", "0", "Jersey filter chain order."); + data("spring.jersey.init", "java.util.Map", null, "Init parameters to pass to Jersey."); + data("spring.jersey.type", "org.springframework.boot.autoconfigure.jersey.JerseyProperties$Type", null, "Jersey integration type. Can be either \"servlet\" or \"filter\"."); + data("spring.jms.jndi-name", "java.lang.String", null, "Connection factory JNDI name. When set, takes precedence to others connection\n factory auto-configurations."); + data("spring.jms.pub-sub-domain", "java.lang.Boolean", "false", "Specify if the default destination type is topic."); + data("spring.jmx.enabled", "java.lang.Boolean", "true", "Expose management beans to the JMX domain."); + data("spring.jpa.database", "org.springframework.orm.jpa.vendor.Database", null, "Target database to operate on, auto-detected by default. Can be alternatively set\n using the \"databasePlatform\" property."); + data("spring.jpa.database-platform", "java.lang.String", null, "Name of the target database to operate on, auto-detected by default. Can be\n alternatively set using the \"Database\" enum."); + data("spring.jpa.generate-ddl", "java.lang.Boolean", "false", "Initialize the schema on startup."); + data("spring.jpa.hibernate.ddl-auto", "java.lang.String", null, "DDL mode (\"none\", \"validate\", \"update\", \"create\", \"create-drop\"). This is\n actually a shortcut for the \"hibernate.hbm2ddl.auto\" property. Default to\n \"create-drop\" when using an embedded database, \"none\" otherwise."); + data("spring.jpa.hibernate.naming-strategy", "java.lang.Class", null, "Naming strategy fully qualified name."); + data("spring.jpa.open-in-view", "java.lang.Boolean", "true", "Register OpenEntityManagerInViewInterceptor. Binds a JPA EntityManager to the thread for the entire processing of the request."); + data("spring.jpa.properties", "java.util.Map", null, "Additional native properties to set on the JPA provider."); + data("spring.jpa.show-sql", "java.lang.Boolean", "false", "Enable logging of SQL statements."); + data("spring.jta.allow-multiple-lrc", "java.lang.Boolean", null, null); + data("spring.jta.asynchronous2-pc", "java.lang.Boolean", null, null); + data("spring.jta.background-recovery-interval", "java.lang.Integer", null, null); + data("spring.jta.background-recovery-interval-seconds", "java.lang.Integer", null, null); + data("spring.jta.current-node-only-recovery", "java.lang.Boolean", null, null); + data("spring.jta.debug-zero-resource-transaction", "java.lang.Boolean", null, null); + data("spring.jta.default-transaction-timeout", "java.lang.Integer", null, null); + data("spring.jta.disable-jmx", "java.lang.Boolean", null, null); + data("spring.jta.enabled", "java.lang.Boolean", "true", "Enable JTA support."); + data("spring.jta.exception-analyzer", "java.lang.String", null, null); + data("spring.jta.filter-log-status", "java.lang.Boolean", null, null); + data("spring.jta.force-batching-enabled", "java.lang.Boolean", null, null); + data("spring.jta.forced-write-enabled", "java.lang.Boolean", null, null); + data("spring.jta.graceful-shutdown-interval", "java.lang.Integer", null, null); + data("spring.jta.jndi-transaction-synchronization-registry-name", "java.lang.String", null, null); + data("spring.jta.jndi-user-transaction-name", "java.lang.String", null, null); + data("spring.jta.journal", "java.lang.String", null, null); + data("spring.jta.log-dir", "java.lang.String", null, "Transaction logs directory."); + data("spring.jta.log-part1-filename", "java.lang.String", null, null); + data("spring.jta.log-part2-filename", "java.lang.String", null, null); + data("spring.jta.max-log-size-in-mb", "java.lang.Integer", null, null); + data("spring.jta.resource-configuration-filename", "java.lang.String", null, null); + data("spring.jta.server-id", "java.lang.String", null, null); + data("spring.jta.skip-corrupted-logs", "java.lang.Boolean", null, null); + data("spring.jta.transaction-manager-id", "java.lang.String", null, "Transaction manager unique identifier."); + data("spring.jta.warn-about-zero-resource-transaction", "java.lang.Boolean", null, null); + data("spring.mail.default-encoding", "java.lang.String", "UTF-8", "Default MimeMessage encoding."); + data("spring.mail.host", "java.lang.String", null, "SMTP server host."); + data("spring.mail.password", "java.lang.String", null, "Login password of the SMTP server."); + data("spring.mail.port", "java.lang.Integer", null, "SMTP server port."); + data("spring.mail.properties", "java.util.Map", null, "Additional JavaMail session properties."); + data("spring.mail.username", "java.lang.String", null, "Login user of the SMTP server."); + data("spring.main.show-banner", "java.lang.Boolean", "true", "Display the banner when the application runs."); + data("spring.main.sources", "java.util.Set", null, "Sources (class name, package name or XML resource location) used to create the ApplicationContext."); + data("spring.main.web-environment", "java.lang.Boolean", null, "Run the application in a web environment (auto-detected by default)."); + data("spring.mandatory-file-encoding", "java.lang.String", null, "Expected character encoding the application must use."); + data("spring.messages.basename", "java.lang.String", "messages", "Comma-separated list of basenames, each following the ResourceBundle convention.\n Essentially a fully-qualified classpath location. If it doesn't contain a package\n qualifier (such as \"org.mypackage\"), it will be resolved from the classpath root."); + data("spring.messages.cache-seconds", "java.lang.Integer", "-1", "Loaded resource bundle files cache expiration, in seconds. When set to -1, bundles\n are cached forever."); + data("spring.messages.encoding", "java.lang.String", "utf-8", "Message bundles encoding."); + data("spring.mobile.devicedelegatingviewresolver.enabled", "java.lang.Boolean", "false", "Enable device view resolver."); + data("spring.mobile.devicedelegatingviewresolver.mobile-prefix", "java.lang.String", "mobile/", "Prefix that gets prepended to view names for mobile devices."); + data("spring.mobile.devicedelegatingviewresolver.mobile-suffix", "java.lang.String", "", "Suffix that gets appended to view names for mobile devices."); + data("spring.mobile.devicedelegatingviewresolver.normal-prefix", "java.lang.String", "", "Prefix that gets prepended to view names for normal devices."); + data("spring.mobile.devicedelegatingviewresolver.normal-suffix", "java.lang.String", "", "Suffix that gets appended to view names for normal devices."); + data("spring.mobile.devicedelegatingviewresolver.tablet-prefix", "java.lang.String", "tablet/", "Prefix that gets prepended to view names for tablet devices."); + data("spring.mobile.devicedelegatingviewresolver.tablet-suffix", "java.lang.String", "", "Suffix that gets appended to view names for tablet devices."); + data("spring.mobile.sitepreference.enabled", "java.lang.Boolean", "true", "Enable SitePreferenceHandler."); + data("spring.mvc.date-format", "java.lang.String", null, "Date format to use (e.g. dd/MM/yyyy)"); + data("spring.mvc.ignore-default-model-on-redirect", "java.lang.Boolean", "true", "If the the content of the \"default\" model should be ignored during redirect\n scenarios."); + data("spring.mvc.locale", "java.lang.String", null, "Locale to use."); + data("spring.mvc.message-codes-resolver-format", "org.springframework.validation.DefaultMessageCodesResolver$Format", null, "Formatting strategy for message codes (PREFIX_ERROR_CODE, POSTFIX_ERROR_CODE)."); + data("spring.profiles.active", "java.lang.String", null, "Comma-separated list of active profiles. Can be overridden by a command line switch."); + data("spring.profiles.include", "java.lang.String", null, "Unconditionally activate the specified comma separated profiles."); + data("spring.rabbitmq.addresses", "java.lang.String", null, "Comma-separated list of addresses to which the client should connect to."); + data("spring.rabbitmq.dynamic", "java.lang.Boolean", "true", "Create an AmqpAdmin bean."); + data("spring.rabbitmq.host", "java.lang.String", "localhost", "RabbitMQ host."); + data("spring.rabbitmq.password", "java.lang.String", null, "Login to authenticate against the broker."); + data("spring.rabbitmq.port", "java.lang.Integer", "5672", "RabbitMQ port."); + data("spring.rabbitmq.username", "java.lang.String", null, "Login user to authenticate to the broker."); + data("spring.rabbitmq.virtual-host", "java.lang.String", null, "Virtual host to use when connecting to the broker."); + data("spring.redis.database", "java.lang.Integer", "0", "Database index used by the connection factory."); + data("spring.redis.host", "java.lang.String", "localhost", "Redis server host."); + data("spring.redis.password", "java.lang.String", null, "Login password of the redis server."); + data("spring.redis.pool.max-active", "java.lang.Integer", "8", "Max number of connections that can be allocated by the pool at a given time.\n Use a negative value for no limit."); + data("spring.redis.pool.max-idle", "java.lang.Integer", "8", "Max number of \"idle\" connections in the pool. Use a negative value to indicate\n an unlimited number of idle connections."); + data("spring.redis.pool.max-wait", "java.lang.Integer", "-1", "Maximum amount of time (in milliseconds) a connection allocation should block\n before throwing an exception when the pool is exhausted. Use a negative value\n to block indefinitely."); + data("spring.redis.pool.min-idle", "java.lang.Integer", "0", "Target for the minimum number of idle connections to maintain in the pool. This\n setting only has an effect if it is positive."); + data("spring.redis.port", "java.lang.Integer", "6379", "Redis server port."); + data("spring.redis.sentinel.master", "java.lang.String", null, "Name of Redis server."); + data("spring.redis.sentinel.nodes", "java.lang.String", null, "Comma-separated list of host:port pairs."); + data("spring.resources.add-mappings", "java.lang.Boolean", "true", "Enable default resource handling."); + data("spring.resources.cache-period", "java.lang.Integer", null, "Cache period for the resources served by the resource handler, in seconds."); + data("spring.social.auto-connection-views", "java.lang.Boolean", "false", "Enable the connection status view for supported providers."); + data("spring.social.facebook.app-id", "java.lang.String", null, "Application id."); + data("spring.social.facebook.app-secret", "java.lang.String", null, "Application secret."); + data("spring.social.linkedin.app-id", "java.lang.String", null, "Application id."); + data("spring.social.linkedin.app-secret", "java.lang.String", null, "Application secret."); + data("spring.social.twitter.app-id", "java.lang.String", null, "Application id."); + data("spring.social.twitter.app-secret", "java.lang.String", null, "Application secret."); + data("spring.thymeleaf.cache", "java.lang.Boolean", "true", "Enable template caching."); + data("spring.thymeleaf.check-template-location", "java.lang.Boolean", "true", "Check that the templates location exists."); + data("spring.thymeleaf.content-type", "java.lang.String", "text/html", "Content-Type value."); + data("spring.thymeleaf.enabled", "java.lang.Boolean", "true", "Enable MVC Thymeleaf view resolution."); + data("spring.thymeleaf.encoding", "java.lang.String", "UTF-8", "Template encoding."); + data("spring.thymeleaf.excluded-view-names", "java.lang.String[]", null, "Comma-separated list of view names that should be excluded from resolution."); + data("spring.thymeleaf.mode", "java.lang.String", "HTML5", "Template mode to be applied to templates. See also StandardTemplateModeHandlers."); + data("spring.thymeleaf.prefix", "java.lang.String", "classpath:/templates/", "Prefix that gets prepended to view names when building a URL."); + data("spring.thymeleaf.suffix", "java.lang.String", ".html", "Suffix that gets appended to view names when building a URL."); + data("spring.thymeleaf.view-names", "java.lang.String[]", null, "Comma-separated list of view names that can be resolved."); + data("spring.velocity.allow-request-override", "java.lang.Boolean", null, "Set whether HttpServletRequest attributes are allowed to override (hide) controller\n generated model attributes of the same name."); + data("spring.velocity.cache", "java.lang.Boolean", null, "Enable template caching."); + data("spring.velocity.char-set", "java.lang.String", null, null); + data("spring.velocity.charset", "java.lang.String", null, "Template encoding."); + data("spring.velocity.check-template-location", "java.lang.Boolean", null, "Check that the templates location exists."); + data("spring.velocity.content-type", "java.lang.String", null, "Content-Type value."); + data("spring.velocity.date-tool-attribute", "java.lang.String", null, "Name of the DateTool helper object to expose in the Velocity context of the view."); + data("spring.velocity.enabled", "java.lang.Boolean", null, "Enable MVC view resolution for this technology."); + data("spring.velocity.expose-request-attributes", "java.lang.Boolean", null, "Set whether all request attributes should be added to the model prior to merging\n with the template."); + data("spring.velocity.expose-session-attributes", "java.lang.Boolean", null, "Set whether all HttpSession attributes should be added to the model prior to\n merging with the template."); + data("spring.velocity.expose-spring-macro-helpers", "java.lang.Boolean", null, "Set whether to expose a RequestContext for use by Spring's macro library, under the\n name \"springMacroRequestContext\"."); + data("spring.velocity.number-tool-attribute", "java.lang.String", null, "Name of the NumberTool helper object to expose in the Velocity context of the view."); + data("spring.velocity.prefer-file-system-access", "java.lang.Boolean", "true", "Prefer file system access for template loading. File system access enables hot\n detection of template changes."); + data("spring.velocity.prefix", "java.lang.String", null, "Prefix that gets prepended to view names when building a URL."); + data("spring.velocity.properties", "java.util.Map", null, "Additional velocity properties."); + data("spring.velocity.request-context-attribute", "java.lang.String", null, "Name of the RequestContext attribute for all views."); + data("spring.velocity.resource-loader-path", "java.lang.String", "classpath:/templates/", "Template path."); + data("spring.velocity.suffix", "java.lang.String", null, "Suffix that gets appended to view names when building a URL."); + data("spring.velocity.toolbox-config-location", "java.lang.String", null, "Velocity Toolbox config location, for example \"/WEB-INF/toolbox.xml\". Automatically\n loads a Velocity Tools toolbox definition file and expose all defined tools in the\n specified scopes."); + data("spring.velocity.view-names", "java.lang.String[]", null, "White list of view names that can be resolved."); + data("spring.view.prefix", "java.lang.String", null, "Spring MVC view prefix."); + data("spring.view.suffix", "java.lang.String", null, "Spring MVC view suffix."); + } + + public boolean isEmpty() { + return datas == null || datas.isEmpty(); + } + + public SpringPropertyIndexProvider getIndexProvider() { + return indexProvider; + } + +} diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/.gitignore b/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/.gitignore similarity index 100% rename from vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/.gitignore rename to vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/.gitignore diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/.mvn/wrapper/maven-wrapper.jar b/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/.mvn/wrapper/maven-wrapper.jar similarity index 100% rename from vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/.mvn/wrapper/maven-wrapper.jar rename to vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/.mvn/wrapper/maven-wrapper.jar diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/.mvn/wrapper/maven-wrapper.properties b/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/.mvn/wrapper/maven-wrapper.properties rename to vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/.mvn/wrapper/maven-wrapper.properties diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/mvnw b/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/mvnw similarity index 100% rename from vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/mvnw rename to vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/mvnw diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/mvnw.cmd b/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/mvnw.cmd similarity index 100% rename from vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/mvnw.cmd rename to vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/mvnw.cmd diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/pom.xml b/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/pom.xml similarity index 100% rename from vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/pom.xml rename to vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/pom.xml diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/src/main/java/org/test/TestScopeAnnotationApplication.java b/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/src/main/java/org/test/TestAnnotationsApplication.java similarity index 64% rename from vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/src/main/java/org/test/TestScopeAnnotationApplication.java rename to vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/src/main/java/org/test/TestAnnotationsApplication.java index 90fb713da..3780b4b75 100644 --- a/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/src/main/java/org/test/TestScopeAnnotationApplication.java +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/src/main/java/org/test/TestAnnotationsApplication.java @@ -4,9 +4,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class TestScopeAnnotationApplication { +public class TestAnnotationsApplication { public static void main(String[] args) { - SpringApplication.run(TestScopeAnnotationApplication.class, args); + SpringApplication.run(TestAnnotationsApplication.class, args); } } diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/src/main/java/org/test/TestScopeCompletion.java b/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/src/main/java/org/test/TestScopeCompletion.java similarity index 100% rename from vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-scope-annotation/src/main/java/org/test/TestScopeCompletion.java rename to vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/src/main/java/org/test/TestScopeCompletion.java diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/src/main/java/org/test/TestValueCompletion.java b/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/src/main/java/org/test/TestValueCompletion.java new file mode 100644 index 000000000..ba853018a --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-projects/test-annotations/src/main/java/org/test/TestValueCompletion.java @@ -0,0 +1,17 @@ +package org.test; + +import org.springframework.beans.factory.annotation.Value; + +public class TestValueCompletion { + + @Value("onField") + private String value1; + + @Value("onMethod") + public void method1() { + } + + public void method2(@Value("onParameter") String parameter1) { + } + +} diff --git a/vscode-extensions/vscode-boot-properties/pom.xml b/vscode-extensions/vscode-boot-properties/pom.xml index 5c8aff563..badc4a90a 100644 --- a/vscode-extensions/vscode-boot-properties/pom.xml +++ b/vscode-extensions/vscode-boot-properties/pom.xml @@ -53,6 +53,11 @@ commons-maven ${project.version} + + org.springframework.ide.vscode + commons-gradle + ${project.version} + org.springframework.ide.vscode commons-language-server diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/BootPropertiesLanguageServer.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/BootPropertiesLanguageServer.java index dd3132a00..067c2c145 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/BootPropertiesLanguageServer.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/BootPropertiesLanguageServer.java @@ -18,12 +18,13 @@ import org.springframework.ide.vscode.boot.common.RelaxedNameConfig; import org.springframework.ide.vscode.boot.metadata.PropertyInfo; import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.boot.metadata.types.TypeUtilProvider; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; import org.springframework.ide.vscode.boot.properties.completions.SpringPropertiesCompletionEngine; import org.springframework.ide.vscode.boot.properties.hover.PropertiesHoverInfoProvider; import org.springframework.ide.vscode.boot.properties.reconcile.SpringPropertiesReconcileEngine; import org.springframework.ide.vscode.boot.yaml.completions.ApplicationYamlAssistContext; import org.springframework.ide.vscode.boot.yaml.reconcile.ApplicationYamlReconcileEngine; +import org.springframework.ide.vscode.commons.gradle.GradleCore; +import org.springframework.ide.vscode.commons.gradle.GradleProjectFinderStrategy; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter; import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider; @@ -36,7 +37,9 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcil import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; import org.springframework.ide.vscode.commons.maven.JavaProjectWithClasspathFileFinderStrategy; +import org.springframework.ide.vscode.commons.maven.MavenCore; import org.springframework.ide.vscode.commons.maven.MavenProjectFinderStrategy; +import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.text.IDocument; import org.springframework.ide.vscode.commons.util.text.TextDocument; import org.springframework.ide.vscode.commons.yaml.ast.YamlASTProvider; @@ -60,7 +63,8 @@ import com.google.common.collect.ImmutableList; public class BootPropertiesLanguageServer extends SimpleLanguageServer { public static final JavaProjectFinder DEFAULT_PROJECT_FINDER = new DefaultJavaProjectFinder(new IJavaProjectFinderStrategy[] { - new MavenProjectFinderStrategy(), + new MavenProjectFinderStrategy(MavenCore.getDefault()), + new GradleProjectFinderStrategy(GradleCore.getDefault()), new JavaProjectWithClasspathFileFinderStrategy() }); diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/CommonLanguageTools.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/CommonLanguageTools.java index 1b75f4878..661e2c7b2 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/CommonLanguageTools.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/CommonLanguageTools.java @@ -26,11 +26,11 @@ import org.springframework.ide.vscode.boot.metadata.types.Type; import org.springframework.ide.vscode.boot.metadata.types.TypeParser; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.EnumCaseMode; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; import org.springframework.ide.vscode.boot.properties.reconcile.PropertyNavigator; import org.springframework.ide.vscode.commons.languageserver.LanguageIds; import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion; import org.springframework.ide.vscode.commons.util.CollectionUtil; +import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.text.TextDocument; diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/PropertyCompletionFactory.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/PropertyCompletionFactory.java index 5ef8fe78d..0d84eb5b9 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/PropertyCompletionFactory.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/PropertyCompletionFactory.java @@ -16,11 +16,11 @@ import org.springframework.ide.vscode.boot.metadata.types.Type; import org.springframework.ide.vscode.boot.metadata.types.TypeParser; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil; import org.springframework.ide.vscode.boot.metadata.types.TypedProperty; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap.Match; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.util.FuzzyMap.Match; import org.springframework.ide.vscode.commons.util.Renderable; import org.springframework.ide.vscode.commons.util.text.IDocument; import org.springframework.ide.vscode.commons.yaml.hover.YPropertyInfoTemplates; diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java index 7a25628b2..2618837bc 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/ClassReferenceProvider.java @@ -131,11 +131,11 @@ public class ClassReferenceProvider extends CachingValueProvider { @Override protected Flux getValuesAsync(IJavaProject javaProject, String query) { - IType targetType = target == null || target.isEmpty() ? javaProject.findType("java.lang.Object") : javaProject.findType(target); + IType targetType = target == null || target.isEmpty() ? javaProject.getClasspath().findType("java.lang.Object") : javaProject.getClasspath().findType(target); if (targetType == null) { return Flux.empty(); } - Set allSubclasses = javaProject + Set allSubclasses = javaProject.getClasspath() .allSubtypesOf(targetType) .filter(t -> Flags.isPublic(t.getFlags()) && !concrete || !isAbstract(t)) .collect(Collectors.toSet()) @@ -143,7 +143,7 @@ public class ClassReferenceProvider extends CachingValueProvider { if (allSubclasses.isEmpty()) { return Flux.empty(); } else { - return javaProject + return javaProject.getClasspath() .fuzzySearchTypes(query, type -> allSubclasses.contains(type)) .collectSortedList((o1, o2) -> o2.getT2().compareTo(o1.getT2())) .flatMap(l -> Flux.fromIterable(l)) diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java index 6434fb19b..685fc56f9 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java @@ -11,13 +11,15 @@ package org.springframework.ide.vscode.boot.metadata; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.ProgressService; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.text.IDocument; public class DefaultSpringPropertyIndexProvider implements SpringPropertyIndexProvider { + + private static final FuzzyMap EMPTY_INDEX = new SpringPropertyIndex(null, null); private JavaProjectFinder javaProjectFinder; private SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(ValueProviderRegistry.getDefault()); @@ -34,7 +36,7 @@ public class DefaultSpringPropertyIndexProvider implements SpringPropertyIndexPr if (jp!=null) { return indexManager.get(jp, progressService); } - return null; + return EMPTY_INDEX; } public void setProgressService(ProgressService progressService) { diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/IndexNavigator.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/IndexNavigator.java index cd19604c6..ffa4f3b6a 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/IndexNavigator.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/IndexNavigator.java @@ -10,14 +10,14 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.metadata; -import static org.springframework.ide.vscode.commons.util.StringUtil.*; +import static org.springframework.ide.vscode.commons.util.StringUtil.hasText; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap.Match; +import org.springframework.ide.vscode.commons.util.FuzzyMap; +import org.springframework.ide.vscode.commons.util.FuzzyMap.Match; import org.springframework.ide.vscode.commons.util.StringUtil; /** diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProvider.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProvider.java index e3fd3ee6e..2f9886766 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProvider.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/LoggerNameProvider.java @@ -37,10 +37,10 @@ public class LoggerNameProvider extends CachingValueProvider { @Override protected Flux getValuesAsync(IJavaProject javaProject, String query) { return Flux.concat( - javaProject + javaProject.getClasspath() .fuzzySearchPackages(query) .map(t -> Tuples.of(StsValueHint.create(t.getT1()), t.getT2())), - javaProject + javaProject.getClasspath() .fuzzySearchTypes(query, null) .map(t -> Tuples.of(StsValueHint.create(t.getT1()), t.getT2())) ) diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java index d88075998..79830ab41 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java @@ -13,11 +13,11 @@ package org.springframework.ide.vscode.boot.metadata; import java.util.HashMap; import java.util.Map; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; import org.springframework.ide.vscode.boot.metadata.util.Listener; import org.springframework.ide.vscode.boot.metadata.util.ListenerManager; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.ProgressService; +import org.springframework.ide.vscode.commons.util.FuzzyMap; /** * Support for Reconciling, Content Assist and Hover Text in spring properties diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndex.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndex.java index b21ed7bef..cc6f74e01 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndex.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndex.java @@ -17,8 +17,8 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataGroup import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; import org.springframework.boot.configurationmetadata.ConfigurationMetadataSource; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; import org.springframework.ide.vscode.commons.java.IClasspath; +import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.StringUtil; public class SpringPropertyIndex extends FuzzyMap { diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndexProvider.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndexProvider.java index 41f750fb0..daad71928 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndexProvider.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndexProvider.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.metadata; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; +import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.text.IDocument; diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/hints/StsValueHint.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/hints/StsValueHint.java index c3f088792..8845e0013 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/hints/StsValueHint.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/hints/StsValueHint.java @@ -79,7 +79,7 @@ public class StsValueHint { try { IJavaProject jp = typeUtil.getJavaProject(); if (jp!=null) { - IType type = jp.findType(fqName); + IType type = jp.getClasspath().findType(fqName); if (type!=null) { return create(type); } diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java index 0a5377962..07bb5c158 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java @@ -543,7 +543,7 @@ public class TypeUtil { private IType findType(String typeName) { try { if (javaProject!=null) { - return javaProject.findType(typeName); + return javaProject.getClasspath().findType(typeName); } } catch (Exception e) { Log.log(e); diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/completions/PropertiesCompletionProposalsCalculator.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/completions/PropertiesCompletionProposalsCalculator.java index 1d28fae29..2b6ff9e5e 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/completions/PropertiesCompletionProposalsCalculator.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/completions/PropertiesCompletionProposalsCalculator.java @@ -11,7 +11,11 @@ package org.springframework.ide.vscode.boot.properties.completions; -import static org.springframework.ide.vscode.boot.common.CommonLanguageTools.*; +import static org.springframework.ide.vscode.boot.common.CommonLanguageTools.SPACES; +import static org.springframework.ide.vscode.boot.common.CommonLanguageTools.findLongestValidProperty; +import static org.springframework.ide.vscode.boot.common.CommonLanguageTools.getValueHints; +import static org.springframework.ide.vscode.boot.common.CommonLanguageTools.getValueType; +import static org.springframework.ide.vscode.boot.common.CommonLanguageTools.isValuePrefixChar; import static org.springframework.ide.vscode.commons.util.StringUtil.camelCaseToHyphens; import java.util.ArrayList; @@ -28,11 +32,9 @@ import org.springframework.ide.vscode.boot.metadata.hints.ValueHintHoverInfo; import org.springframework.ide.vscode.boot.metadata.types.Type; import org.springframework.ide.vscode.boot.metadata.types.TypeParser; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil; -import org.springframework.ide.vscode.boot.metadata.types.TypedProperty; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.BeanPropertyNameMode; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.EnumCaseMode; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap.Match; +import org.springframework.ide.vscode.boot.metadata.types.TypedProperty; import org.springframework.ide.vscode.boot.properties.reconcile.PropertyNavigator; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; @@ -41,6 +43,8 @@ import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion import org.springframework.ide.vscode.commons.languageserver.util.PrefixFinder; import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.CollectionUtil; +import org.springframework.ide.vscode.commons.util.FuzzyMap; +import org.springframework.ide.vscode.commons.util.FuzzyMap.Match; import org.springframework.ide.vscode.commons.util.FuzzyMatcher; import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.text.IDocument; diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverCalculator.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverCalculator.java index 603c5f1ea..cfdb1dc2c 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverCalculator.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverCalculator.java @@ -29,10 +29,10 @@ import org.springframework.ide.vscode.boot.metadata.hints.StsValueHint; import org.springframework.ide.vscode.boot.metadata.types.Type; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.EnumCaseMode; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion; import org.springframework.ide.vscode.commons.util.BadLocationException; +import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.Renderable; import org.springframework.ide.vscode.commons.util.text.IDocument; import org.springframework.ide.vscode.commons.util.text.IRegion; diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java index 06df1224f..7a19d1d46 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java @@ -25,12 +25,12 @@ import org.springframework.ide.vscode.boot.metadata.types.Type; import org.springframework.ide.vscode.boot.metadata.types.TypeParser; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil; import org.springframework.ide.vscode.boot.metadata.types.TypeUtilProvider; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; import org.springframework.ide.vscode.boot.properties.quickfix.ReplaceDeprecatedPropertyQuickfix; import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine; import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion; import org.springframework.ide.vscode.commons.util.BadLocationException; +import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.ValueParser; import org.springframework.ide.vscode.commons.util.text.IDocument; diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java index 4e75f3eca..1c7948bc3 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java @@ -17,7 +17,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Stream; import org.springframework.boot.configurationmetadata.Deprecation; import org.springframework.ide.vscode.boot.common.InformationTemplates; @@ -34,8 +33,6 @@ import org.springframework.ide.vscode.boot.metadata.types.TypeUtil; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.BeanPropertyNameMode; import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.EnumCaseMode; import org.springframework.ide.vscode.boot.metadata.types.TypedProperty; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap.Match; import org.springframework.ide.vscode.commons.java.IField; import org.springframework.ide.vscode.commons.java.IJavaElement; import org.springframework.ide.vscode.commons.java.IMember; @@ -46,6 +43,8 @@ import org.springframework.ide.vscode.commons.languageserver.completion.LazyProp import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal; import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion; import org.springframework.ide.vscode.commons.util.CollectionUtil; +import org.springframework.ide.vscode.commons.util.FuzzyMap; +import org.springframework.ide.vscode.commons.util.FuzzyMap.Match; import org.springframework.ide.vscode.commons.util.FuzzyMatcher; import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.Renderable; diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java index 1835a1682..f7670fe3f 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java @@ -16,9 +16,9 @@ import org.springframework.ide.vscode.boot.metadata.IndexNavigator; import org.springframework.ide.vscode.boot.metadata.PropertyInfo; import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.boot.metadata.types.TypeUtilProvider; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; +import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.text.IDocument; import org.springframework.ide.vscode.commons.yaml.ast.YamlASTProvider; import org.springframework.ide.vscode.commons.yaml.reconcile.YamlASTReconciler; diff --git a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java index 0a727548d..4b74d7e51 100644 --- a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java +++ b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java @@ -22,9 +22,9 @@ import org.springframework.ide.vscode.boot.metadata.PropertyInfo; import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndex; import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; import org.springframework.ide.vscode.commons.java.IClasspath; import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.text.IDocument; /** diff --git a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/metadata/PropertiesIndexTest.java b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/metadata/PropertiesIndexTest.java index 4fd9ae0b4..f0df01135 100644 --- a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/metadata/PropertiesIndexTest.java +++ b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/metadata/PropertiesIndexTest.java @@ -15,12 +15,9 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import org.junit.Test; -import org.springframework.ide.vscode.boot.metadata.PropertyInfo; -import org.springframework.ide.vscode.boot.metadata.SpringPropertiesIndexManager; -import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry; -import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.ProgressService; +import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.project.harness.ProjectsHarness; /** diff --git a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/metadata/TypeUtilTest.java b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/metadata/TypeUtilTest.java index 139e550e6..40f29fe16 100644 --- a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/metadata/TypeUtilTest.java +++ b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/metadata/TypeUtilTest.java @@ -68,8 +68,8 @@ public class TypeUtilTest { @Test public void testGetProperties() throws Exception { useProject("enums-boot-1.3.2-app"); - assertNotNull(project.findType("demo.Color")); - assertNotNull(project.findType("demo.ColorData")); + assertNotNull(project.getClasspath().findType("demo.Color")); + assertNotNull(project.getClasspath().findType("demo.ColorData")); Type data = TypeParser.parse("demo.ColorData"); diff --git a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java index 5ea78f46f..0c6320e80 100644 --- a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java +++ b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java @@ -214,7 +214,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { @Test public void testPredefinedProject() throws Exception { IJavaProject p = createPredefinedMavenProject("tricky-getters-boot-1.3.1-app"); - IType type = p.findType("demo.DemoApplication"); + IType type = p.getClasspath().findType("demo.DemoApplication"); assertNotNull(type); } @@ -223,7 +223,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { //Check some assumptions about the initial state of the test project (if these checks fail then // the test may be 'vacuous' since the things we are testing for already exist beforehand. - Path metadataFile = p.getOutputFolder().resolve(PropertiesLoader.PROJECT_META_DATA_LOCATIONS[0]); + Path metadataFile = p.getClasspath().getOutputFolder().resolve(PropertiesLoader.PROJECT_META_DATA_LOCATIONS[0]); assertTrue(metadataFile.toFile().isFile()); assertContains("\"name\": \"foo.counter\"", Files.toString(metadataFile.toFile(), Charset.forName("UTF8"))); } @@ -288,7 +288,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("boot-1.2.1-app-properties-list-of-pojo"); useProject(p); - assertNotNull(p.findType("demo.Foo")); + assertNotNull(p.getClasspath().findType("demo.Foo")); Editor editor = newEditor( "token.bad.guy=problem\n"+ @@ -313,7 +313,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("boot-1.2.1-app-properties-list-of-pojo"); useProject(p); - assertNotNull(p.findType("demo.Foo")); + assertNotNull(p.getClasspath().findType("demo.Foo")); assertCompletionsVariations("volder.foo.l<*>", "volder.foo.list[<*>"); assertCompletionsDisplayStringAndDetail("volder.foo.list[0].<*>", @@ -462,7 +462,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.Color")); data("foo.colors", "java.util.List", null, "A foonky list"); @@ -485,7 +485,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.Color")); data("foo.color", "demo.Color", null, "A foonky colour"); @@ -504,7 +504,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.Color")); data("foo.color", "demo.Color", null, "A foonky colour"); Editor editor = newEditor( @@ -527,7 +527,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.Color")); assertCompletionsVariations("foo.nam<*>", "foo.name-colors.<*>", @@ -546,7 +546,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { useProject(p); data("foo.name-colors", "java.util.Map", null, "Map with colors in its values"); - assertNotNull(p.findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.Color")); Editor editor = newEditor( "foo.name-colors.jacket=BLUE\n" + @@ -565,8 +565,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { useProject(p); data("foo.color-names", "java.util.Map", null, "Map with colors in its keys"); data("foo.color-data", "java.util.Map", null, "Map with colors in its keys, and pojo in values"); - assertNotNull(p.findType("demo.Color")); - assertNotNull(p.findType("demo.ColorData")); + assertNotNull(p.getClasspath().findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.ColorData")); //Map Enum -> String: assertCompletionsVariations("foo.colnam<*>", "foo.color-names.<*>"); @@ -605,8 +605,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.Color")); - assertNotNull(p.findType("demo.ColorData")); + assertNotNull(p.getClasspath().findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.ColorData")); Editor editor = newEditor( "foo.color-names.RED=Rood\n"+ @@ -625,8 +625,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.Color")); - assertNotNull(p.findType("demo.ColorData")); + assertNotNull(p.getClasspath().findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.ColorData")); assertCompletion("foo.dat<*>", "foo.data.<*>"); @@ -660,8 +660,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.Color")); - assertNotNull(p.findType("demo.ColorData")); + assertNotNull(p.getClasspath().findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.ColorData")); Editor editor = newEditor( "foo.data.bogus=Something\n" + @@ -695,8 +695,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.Color")); - assertNotNull(p.findType("demo.ColorData")); + assertNotNull(p.getClasspath().findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.ColorData")); data("atommap", "java.util.Map", null, "map of atomic data"); data("objectmap", "java.util.Map", null, "map of atomic object (recursive map)"); @@ -735,8 +735,8 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.Color")); - assertNotNull(p.findType("demo.ColorData")); + assertNotNull(p.getClasspath().findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.ColorData")); Editor editor = newEditor( "foo.color-names.BLUE.dot=Blauw\n"+ @@ -761,7 +761,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.ClothingSize")); + assertNotNull(p.getClasspath().findType("demo.ClothingSize")); data("simple.pants.size", "demo.ClothingSize", null, "The simple pant's size"); @@ -805,7 +805,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.ClothingSize")); + assertNotNull(p.getClasspath().findType("demo.ClothingSize")); data("simple.pants.size", "demo.ClothingSize", null, "The simple pant's size"); @@ -1400,7 +1400,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.Color")); data("my.colors", "java.util.List", null, "Ooh! nice colors!"); diff --git a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java index 860baf75d..f42afb166 100644 --- a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java +++ b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java @@ -545,7 +545,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { @Test public void testReconcileBeanPropName() throws Exception { IJavaProject p = createPredefinedMavenProject("boot-1.2.1-app-properties-list-of-pojo"); useProject(p); - assertNotNull(p.findType("demo.Foo")); + assertNotNull(p.getClasspath().findType("demo.Foo")); data("some-foo", "demo.Foo", null, "some Foo pojo property"); Editor editor = newEditor( "some-foo:\n" + @@ -577,7 +577,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { @Test public void testReconcilePojoArray() throws Exception { IJavaProject p = createPredefinedMavenProject("boot-1.2.1-app-properties-list-of-pojo"); useProject(p); - assertNotNull(p.findType("demo.Foo")); + assertNotNull(p.getClasspath().findType("demo.Foo")); { Editor editor = newEditor( @@ -654,7 +654,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { @Test public void testEnumPropertyReconciling() throws Exception { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.Color")); + assertNotNull(p.getClasspath().findType("demo.Color")); data("foo.color", "demo.Color", null, "A foonky colour"); Editor editor = newEditor( @@ -1846,7 +1846,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { @Ignore @Test public void testEnumsInLowerCaseContentAssist() throws Exception { IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app"); useProject(p); - assertNotNull(p.findType("demo.ClothingSize")); + assertNotNull(p.getClasspath().findType("demo.ClothingSize")); data("simple.pants.size", "demo.ClothingSize", null, "The simple pant's size"); diff --git a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/project/harness/ProjectsHarness.java b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/project/harness/ProjectsHarness.java index 56fda5153..bde1c3f47 100644 --- a/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/project/harness/ProjectsHarness.java +++ b/vscode-extensions/vscode-boot-properties/src/test/java/org/springframework/ide/vscode/project/harness/ProjectsHarness.java @@ -52,7 +52,7 @@ public class ProjectsHarness { switch (type) { case MAVEN: MavenBuilder.newBuilder(testProjectPath).clean().pack().javadoc().skipTests().execute(); - return new MavenJavaProject(testProjectPath.resolve(MavenCore.POM_XML).toFile()); + return new MavenJavaProject(MavenCore.getDefault(), testProjectPath.resolve(MavenCore.POM_XML).toFile()); case CLASSPATH_TXT: MavenBuilder.newBuilder(testProjectPath).clean().pack().skipTests().execute(); return new JavaProjectWithClasspathFile(testProjectPath.resolve(MavenCore.CLASSPATH_TXT).toFile()); diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlCFDomainsProvider.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlCFDomainsProvider.java new file mode 100644 index 000000000..4617dbcf9 --- /dev/null +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlCFDomainsProvider.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * 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.manifest.yaml; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.ide.vscode.commons.cloudfoundry.client.CFDomain; +import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTarget; +import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetCache; +import org.springframework.ide.vscode.commons.yaml.schema.BasicYValueHint; +import org.springframework.ide.vscode.commons.yaml.schema.YValueHint; + +public class ManifestYamlCFDomainsProvider extends AbstractCFHintsProvider { + + public ManifestYamlCFDomainsProvider(CFTargetCache cache) { + super(cache); + } + + @Override + public Collection getHints(List targets) throws Exception { + + List hints = new ArrayList<>(); + + for (CFTarget cfTarget : targets) { + + List domains = cfTarget.getDomains(); + if (domains != null && !domains.isEmpty()) { + + for (CFDomain domain : domains) { + String name = domain.getName(); + String label = getLabel(cfTarget, domain); + YValueHint hint = new BasicYValueHint(name, label); + if (!hints.contains(hint)) { + hints.add(hint); + } + } + return hints; + } + } + // Contract for the reconciler: return null if values cannot be + // resolved. Otherwise + // return non-empty list + return !hints.isEmpty() ? hints : null; + } + + protected String getLabel(CFTarget target, CFDomain domain) { + return domain.getName(); + } + + @Override + protected String getTypeName() { + return "Domain"; + } +} diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java index f1fe59da7..bce95e518 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java @@ -63,10 +63,7 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { YamlASTProvider parser = new YamlParser(yaml); - Callable> buildPacksProvider = getBuildpacksProvider(); - Callable> servicesProvider = getServicesProvider(); - - schema = new ManifestYmlSchema(buildPacksProvider, servicesProvider); + schema = new ManifestYmlSchema(getHintProviders()); YamlStructureProvider structureProvider = YamlStructureProvider.DEFAULT; YamlAssistContextProvider contextProvider = new SchemaBasedYamlAssistContextProvider(schema); @@ -98,6 +95,30 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { documents.onHover(hoverEngine ::getHover); } + protected ManifestYmlHintProviders getHintProviders() { + Callable> buildPacksProvider = getBuildpacksProvider(); + Callable> servicesProvider = getServicesProvider(); + Callable> domainsProvider = getDomainsProvider(); + + return new ManifestYmlHintProviders() { + + @Override + public Callable> getServicesProvider() { + return servicesProvider; + } + + @Override + public Callable> getDomainsProvider() { + return domainsProvider; + } + + @Override + public Callable> getBuildpackProviders() { + return buildPacksProvider; + } + }; + } + private CFTargetCache getCfTargetCache() { if (cfTargetCache == null) { ClientParamsProvider paramsProvider = cfParamsProvider; @@ -114,6 +135,10 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { private Callable> getServicesProvider() { return new ManifestYamlCFServicesProvider(getCfTargetCache()); } + + private Callable> getDomainsProvider() { + return new ManifestYamlCFDomainsProvider(getCfTargetCache()); + } @Override protected ServerCapabilities getServerCapabilities() { diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlHintProviders.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlHintProviders.java new file mode 100644 index 000000000..09558ba5b --- /dev/null +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlHintProviders.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * 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.manifest.yaml; + +import java.util.Collection; +import java.util.concurrent.Callable; + +import org.springframework.ide.vscode.commons.yaml.schema.YValueHint; + +public interface ManifestYmlHintProviders { + + Callable> getBuildpackProviders(); + + Callable> getServicesProvider(); + + Callable> getDomainsProvider(); + +} diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java index 8f2e0f722..1974ca8c5 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java @@ -22,6 +22,7 @@ import org.springframework.ide.vscode.commons.yaml.schema.YType; import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory; import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.AbstractType; import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YAtomicType; +import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YBeanType; import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YTypedPropertyImpl; import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil; import org.springframework.ide.vscode.commons.yaml.schema.YValueHint; @@ -47,8 +48,13 @@ public class ManifestYmlSchema implements YamlSchema { return IntegerRange.exactly(1); } - public ManifestYmlSchema(Callable> buildpackProvider, Callable> servicesProvider) { - this.buildpackProvider = buildpackProvider; + + public ManifestYmlSchema(ManifestYmlHintProviders providers) { + this.buildpackProvider = providers.getBuildpackProviders(); + Callable> servicesProvider = providers.getServicesProvider(); + Callable> domainsProvider = providers.getDomainsProvider(); + + YTypeFactory f = new YTypeFactory(); TYPE_UTIL = f.TYPE_UTIL; @@ -63,7 +69,17 @@ public class ManifestYmlSchema implements YamlSchema { t_buildpack.addHintProvider(this.buildpackProvider); // t_buildpack.parseWith(ManifestYmlValueParsers.fromHints(t_buildpack.toString(), buildpackProvider)); } + + YAtomicType t_domain = f.yatomic("Domain"); + YAtomicType t_domains_string = f.yatomic("Domains"); + if (domainsProvider != null) { + t_domain.addHintProvider(domainsProvider); + t_domains_string.addHintProvider(domainsProvider); + } + + YType t_domains = f.yseq(t_domains_string); + YAtomicType t_service_string = f.yatomic("Service"); if (servicesProvider != null) { t_service_string.addHintProvider(servicesProvider); @@ -78,6 +94,13 @@ public class ManifestYmlSchema implements YamlSchema { YType t_string = f.yatomic("String"); YType t_strings = f.yseq(t_string); + // "routes" has nested required property "route": + // routes: + // - route: someroute.io + + YBeanType route = f.ybean("Route"); + route.addProperty(f.yprop("route", t_string).isRequired(true)); + YAtomicType t_memory = f.yatomic("Memory"); t_memory.addHints("256M", "512M", "1024M"); t_memory.parseWith(ManifestYmlValueParsers.MEMORY); @@ -112,8 +135,8 @@ public class ManifestYmlSchema implements YamlSchema { f.yprop("buildpack", t_buildpack), f.yprop("command", t_string), f.yprop("disk_quota", t_memory), - f.yprop("domain", t_string), - f.yprop("domains", t_strings), + f.yprop("domain", t_domain), + f.yprop("domains", t_domains), f.yprop("env", t_env), f.yprop("host", t_string), f.yprop("hosts", t_strings), @@ -124,6 +147,7 @@ public class ManifestYmlSchema implements YamlSchema { f.yprop("no-route", t_boolean), f.yprop("path", t_path), f.yprop("random-route", t_boolean), + f.yprop("routes", f.yseq(route)), f.yprop("services", t_services), f.yprop("stack", t_string), f.yprop("timeout", t_pos_integer), diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/resources/description-by-prop-name/routes.html b/vscode-extensions/vscode-manifest-yaml/src/main/resources/description-by-prop-name/routes.html new file mode 100644 index 000000000..49b219ea2 --- /dev/null +++ b/vscode-extensions/vscode-manifest-yaml/src/main/resources/description-by-prop-name/routes.html @@ -0,0 +1,12 @@ +

    Use the routes attribute to provide multiple HTTP and TCP routes. Each route for this app is created if it does not already exist.

    +

    This attribute is a combination of push options that include --hostname, -d, and --route-path.

    +
    +---
    +  ...
    +  routes:
    +  - route: example.com
    +  - route: www.example.com/foo
    +  - route: tcp-example.com:1234
    +
    + +

    The routes attribute cannot be used in conjunction with the following attributes: host, hosts, domain, domains, and no-hostname. An error will result.

    diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/resources/description-by-prop-name/routes.md b/vscode-extensions/vscode-manifest-yaml/src/main/resources/description-by-prop-name/routes.md new file mode 100644 index 000000000..754921e46 --- /dev/null +++ b/vscode-extensions/vscode-manifest-yaml/src/main/resources/description-by-prop-name/routes.md @@ -0,0 +1,14 @@ +Use the `routes` attribute to provide multiple HTTP and TCP routes. Each route for this app is created if it does not already exist. + +This attribute is a combination of `push` options that include `--hostname`, `-d`, and `--route-path`. + +``` +--- + ... + routes: + - route: example.com + - route: www.example.com/foo + - route: tcp-example.com:1234 +``` + +The `routes` attribute cannot be used in conjunction with the following attributes: `host`, `hosts`, `domain`, `domains`, and `no-hostname`. An error will result. \ No newline at end of file diff --git a/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java b/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java index 4444cf279..8534b6806 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java +++ b/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Pivotal, Inc. +f * 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 @@ -25,6 +25,7 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFBuildpack; +import org.springframework.ide.vscode.commons.cloudfoundry.client.CFDomain; import org.springframework.ide.vscode.commons.cloudfoundry.client.CFServiceInstance; import org.springframework.ide.vscode.commons.cloudfoundry.client.ClientRequests; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.NoTargetsException; @@ -278,6 +279,9 @@ public class ManifestYamlEditorTest { // --------------- "random-route: <*>", // --------------- + "routes:\n"+ + "- <*>", + // --------------- "services:\n"+ "- <*>", // --------------- @@ -353,6 +357,10 @@ public class ManifestYamlEditorTest { "- random-route: <*>", // --------------- "applications:\n" + + "- routes:\n"+ + " - <*>", + // --------------- + "applications:\n" + "- services:\n"+ " - <*>", // --------------- @@ -431,6 +439,8 @@ public class ManifestYamlEditorTest { " no-route: true\n" + " path: somepath/app.jar\n" + " random-route: true\n" + + " routes:\n" + + " - route: tcp-example.com:1234\n" + " services:\n" + " - instance_ABC\n" + " - instance_XYZ\n" + @@ -456,6 +466,7 @@ public class ManifestYamlEditorTest { editor.assertIsHoverRegion("no-route"); editor.assertIsHoverRegion("path"); editor.assertIsHoverRegion("random-route"); + editor.assertIsHoverRegion("routes"); editor.assertIsHoverRegion("services"); editor.assertIsHoverRegion("stack"); editor.assertIsHoverRegion("timeout"); @@ -478,6 +489,7 @@ public class ManifestYamlEditorTest { editor.assertHoverContains("no-route", "You can use the `no-route` attribute with a value of `true` to prevent a route from being created for your application"); editor.assertHoverContains("path", "You can use the `path` attribute to tell Cloud Foundry where to find your application"); editor.assertHoverContains("random-route", "Use the `random-route` attribute to create a URL that includes the app name and random words"); + editor.assertHoverContains("routes", "Each route for this app is created if it does not already exist"); editor.assertHoverContains("services", "The `services` block consists of a heading, then one or more service instance names"); editor.assertHoverContains("stack", "Use the `stack` attribute to specify which stack to deploy your application to."); editor.assertHoverContains("timeout", "The `timeout` attribute defines the number of seconds Cloud Foundry allocates for starting your application"); @@ -595,6 +607,10 @@ public class ManifestYamlEditorTest { "- random-route: <*>", // --------------- "applications:\n" + + "- routes:\n"+ + " - <*>", + // --------------- + "applications:\n" + "- services:\n"+ " - <*>", // --------------- @@ -679,6 +695,11 @@ public class ManifestYamlEditorTest { "- name: test" , // --------------------- "applications:\n" + + "- routes:\n" + + " - <*>\n" + + "- name: test" + ,// --------------------- + "applications:\n" + "- services:\n" + " - <*>\n" + "- name: test" @@ -936,6 +957,44 @@ public class ManifestYamlEditorTest { when(cfClient.getBuildpacks()).thenReturn(ImmutableList.of(buildPack)); assertDoesNotContainCompletions("buildpack: <*>", "buildpack: wrong_buildpack<*>"); } + + @Test + public void domainContentAssist() throws Exception { + ClientRequests cfClient = cloudfoundry.client; + CFDomain domain = Mockito.mock(CFDomain.class); + when(domain.getName()).thenReturn("cfapps.io"); + when(cfClient.getDomains()).thenReturn(ImmutableList.of(domain)); + + assertContainsCompletions("domain: <*>", "domain: cfapps.io<*>"); + } + + @Test + public void domainContentAssistDoesNotContainCompletion() throws Exception { + ClientRequests cfClient = cloudfoundry.client; + CFDomain domain = Mockito.mock(CFDomain.class); + when(domain.getName()).thenReturn("cfapps.io"); + when(cfClient.getDomains()).thenReturn(ImmutableList.of(domain)); + assertDoesNotContainCompletions("domain: <*>", "domain: wrong.cfapps.io<*>"); + } + + @Test + public void domainsContentAssist() throws Exception { + ClientRequests cfClient = cloudfoundry.client; + CFDomain domain = Mockito.mock(CFDomain.class); + when(domain.getName()).thenReturn("cfapps.io"); + when(cfClient.getDomains()).thenReturn(ImmutableList.of(domain)); + + assertContainsCompletions("domains:\n" + " - <*>", "cfapps.io"); + } + + @Test + public void domainsContentAssistWrongDomain() throws Exception { + ClientRequests cfClient = cloudfoundry.client; + CFDomain domain = Mockito.mock(CFDomain.class); + when(domain.getName()).thenReturn("cfapps.io"); + when(cfClient.getDomains()).thenReturn(ImmutableList.of(domain)); + assertDoesNotContainCompletions("domains:\n" + " - <*>", "wrong.cfapps.io"); + } ////////////////////////////////////////////////////////////////////////////// diff --git a/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchemaTest.java b/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchemaTest.java index 5d7af42c8..1c98a65bd 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchemaTest.java +++ b/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchemaTest.java @@ -14,13 +14,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; import org.junit.Test; import org.springframework.ide.vscode.commons.util.Renderables; import org.springframework.ide.vscode.commons.util.StringUtil; import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty; +import org.springframework.ide.vscode.commons.yaml.schema.YValueHint; import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.AbstractType; import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YSeqType; import org.springframework.ide.vscode.manifest.yaml.ManifestYmlSchema; @@ -52,6 +55,7 @@ public class ManifestYmlSchemaTest { "no-route", "path", "random-route", + "routes", "services", "stack", "timeout" @@ -76,12 +80,13 @@ public class ManifestYmlSchemaTest { "no-route", "path", "random-route", + "routes", "services", "stack", "timeout" }; - ManifestYmlSchema schema = new ManifestYmlSchema(null, null); + ManifestYmlSchema schema = new ManifestYmlSchema(EMPTY_PROVIDERS); @Test public void toplevelProperties() throws Exception { @@ -150,5 +155,22 @@ public class ManifestYmlSchemaTest { } return builder.build(); } - + + private static final ManifestYmlHintProviders EMPTY_PROVIDERS = new ManifestYmlHintProviders() { + + @Override + public Callable> getServicesProvider() { + return null; + } + + @Override + public Callable> getDomainsProvider() { + return null; + } + + @Override + public Callable> getBuildpackProviders() { + return null; + } + }; }