This is an automated email from the ASF dual-hosted git repository. entl pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push: new 41da357 Apply LSP URI translation to debugger as well. URI translation cache is created. 41da357 is described below commit 41da35720129ef4f4b7c94bd22ef230ead719153 Author: Martin Entlicher <martin.entlic...@oracle.com> AuthorDate: Mon Oct 11 07:34:07 2021 +0200 Apply LSP URI translation to debugger as well. URI translation cache is created. --- .../modules/java/lsp/server/URITranslator.java | 183 +++++++++++++++++++++ .../netbeans/modules/java/lsp/server/Utils.java | 89 +--------- .../lsp/server/debugging/NbProtocolServer.java | 2 + .../lsp/server/debugging/NbSourceProvider.java | 2 + .../breakpoints/NbBreakpointsRequestHandler.java | 2 + 5 files changed, 191 insertions(+), 87 deletions(-) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/URITranslator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/URITranslator.java new file mode 100644 index 0000000..a68f2f2 --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/URITranslator.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.java.lsp.server; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; + +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.filesystems.URLMapper; +import org.openide.modules.Places; +import org.openide.util.Exceptions; + +/** + * Translation between NetBeans URIs and LSP URIs. LSP clients might not like + * archive URIs. The archive URIs are translated to plain file URIs from a cache + * directory. + */ +public final class URITranslator { + + private static final URITranslator INSTANCE = new URITranslator(); + + private final Map<String, String> uriFromCacheMap = new LRUCacheMap(); + private final Map<String, String> uriToCacheMap = new LRUCacheMap(); + + public static URITranslator getDefault() { + return INSTANCE; + } + + public synchronized String uriToLSP(String lspUri) { + return uriFromCacheMap.computeIfAbsent(lspUri, uri -> { + URI uriUri = URI.create(uri); + URL url; + try { + url = uriUri.toURL(); + } catch (MalformedURLException ex) { + return uri; + } + if (FileUtil.isArchiveArtifact(url)) { + FileObject file = URLMapper.findFileObject(url); + if (file == null) { + return uri; + } + File cacheDir = getCacheDir(); + cacheDir.mkdirs(); + File segments = new File(cacheDir, "segments"); // NOI18N + Properties props = new Properties(); + + try (InputStream in = new FileInputStream(segments)) { + props.load(in); + } catch (IOException ex) { + //OK, may not exist yet + } + FileObject archive = FileUtil.getArchiveFile(file); + String archiveString = archive.toURL().toString(); + File foundSegment = null; + for (String segment : props.stringPropertyNames()) { + if (archiveString.equals(props.getProperty(segment))) { + foundSegment = new File(cacheDir, segment); + break; + } + } + if (foundSegment == null) { + int i = 0; + while (props.getProperty("s" + i) != null) { // NOI18N + i++; + } + foundSegment = new File(cacheDir, "s" + i); // NOI18N + props.put("s" + i, archiveString); // NOI18N + try (OutputStream in = new FileOutputStream(segments)) { + props.store(in, ""); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + File cache = new File(foundSegment, FileUtil.getRelativePath(FileUtil.getArchiveRoot(archive), file)); + cache.getParentFile().mkdirs(); + try (OutputStream out = new FileOutputStream(cache)) { + out.write(file.asBytes()); + return cache.toURI().toString(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + if (uriUri.getScheme().equals("nbfs")) { // NOI18N + FileObject file = URLMapper.findFileObject(url); + if (file == null) { + return uri; + } + try { + String txt = file.asText("UTF-8"); // NOI18N + try (OutputStream os = file.getOutputStream()) { + os.write(txt.getBytes("UTF-8")); // NOI18N + } + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + try { + uri = URLMapper.findURL(file, URLMapper.EXTERNAL).toURI().toString(); + } catch (URISyntaxException ex) { + Exceptions.printStackTrace(ex); + } + } + return uri; + }); + } + + public synchronized String uriFromLSP(String nbUri) { + return uriToCacheMap.computeIfAbsent(nbUri, uri -> { + URI uriUri = URI.create(uri); + File cacheDir = getCacheDir(); + URI relative = cacheDir.toURI().relativize(uriUri); + if (relative != null && new File(cacheDir, relative.toString()).canRead()) { + String segmentAndPath = relative.toString(); + int slash = segmentAndPath.indexOf('/'); + String segment = segmentAndPath.substring(0, slash); + String path = segmentAndPath.substring(slash + 1); + File segments = new File(cacheDir, "segments"); // NOI18N + Properties props = new Properties(); + + try (InputStream in = new FileInputStream(segments)) { + props.load(in); + String archiveUri = props.getProperty(segment); + FileObject archive = URLMapper.findFileObject(URI.create(archiveUri).toURL()); + archive = archive != null ? FileUtil.getArchiveRoot(archive) : null; + FileObject file = archive != null ? archive.getFileObject(path) : null; + if (file != null) { + return file.toURI().toString(); + } + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + return uri; + }); + } + + private static File getCacheDir() { + return Places.getCacheSubfile("java-server"); // NOI18N + } + + private static class LRUCacheMap extends LinkedHashMap<String, String> { + + private static final int MAX_SIZE = 2048; + + LRUCacheMap() { + super(32, 0.75f, true); + } + + @Override + protected boolean removeEldestEntry(Map.Entry<String, String> eldest) { + return size() > MAX_SIZE; + } + + } +} diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java index 309a3de..ec5af37 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java @@ -132,99 +132,14 @@ public class Utils { } public static synchronized String toUri(FileObject file) { - if (FileUtil.isArchiveArtifact(file)) { - //VS code cannot open jar:file: URLs, workaround: - File cacheDir = getCacheDir(); - cacheDir.mkdirs(); - File segments = new File(cacheDir, "segments"); - Properties props = new Properties(); - - try (InputStream in = new FileInputStream(segments)) { - props.load(in); - } catch (IOException ex) { - //OK, may not exist yet - } - FileObject archive = FileUtil.getArchiveFile(file); - String archiveString = archive.toURL().toString(); - File foundSegment = null; - for (String segment : props.stringPropertyNames()) { - if (archiveString.equals(props.getProperty(segment))) { - foundSegment = new File(cacheDir, segment); - break; - } - } - if (foundSegment == null) { - int i = 0; - while (props.getProperty("s" + i) != null) - i++; - foundSegment = new File(cacheDir, "s" + i); - props.put("s" + i, archiveString); - try (OutputStream in = new FileOutputStream(segments)) { - props.store(in, ""); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - } - File cache = new File(foundSegment, FileUtil.getRelativePath(FileUtil.getArchiveRoot(archive), file)); - cache.getParentFile().mkdirs(); - try (OutputStream out = new FileOutputStream(cache)) { - out.write(file.asBytes()); - return cache.toURI().toString(); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - } - URI uri = file.toURI(); - if (uri.getScheme().equals("nbfs")) { - try { - String txt = file.asText("UTF-8"); - try (OutputStream os = file.getOutputStream()) { - os.write(txt.getBytes("UTF-8")); - } - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - try { - uri = URLMapper.findURL(file, URLMapper.EXTERNAL).toURI(); - } catch (URISyntaxException ex) { - Exceptions.printStackTrace(ex); - } - } - return uri.toString(); + return URITranslator.getDefault().uriToLSP(file.toURI().toString()); } public static synchronized FileObject fromUri(String uri) throws MalformedURLException { - File cacheDir = getCacheDir(); - URI uriUri = URI.create(uri); - URI relative = cacheDir.toURI().relativize(uriUri); - if (relative != null && new File(cacheDir, relative.toString()).canRead()) { - String segmentAndPath = relative.toString(); - int slash = segmentAndPath.indexOf('/'); - String segment = segmentAndPath.substring(0, slash); - String path = segmentAndPath.substring(slash + 1); - File segments = new File(cacheDir, "segments"); - Properties props = new Properties(); - - try (InputStream in = new FileInputStream(segments)) { - props.load(in); - String archiveUri = props.getProperty(segment); - FileObject archive = URLMapper.findFileObject(URI.create(archiveUri).toURL()); - archive = archive != null ? FileUtil.getArchiveRoot(archive) : null; - FileObject file = archive != null ? archive.getFileObject(path) : null; - if (file != null) { - return file; - } - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - } + uri = URITranslator.getDefault().uriFromLSP(uri); return URLMapper.findFileObject(URI.create(uri).toURL()); } - private static File getCacheDir() { - return Places.getCacheSubfile("java-server"); - } - private static final char[] SNIPPET_ESCAPE_CHARS = new char[] { '\\', '$', '}' }; /** * Escape special characters in a completion snippet. Characters '$' and '}' diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java index 08b133b..7807fdb 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java @@ -80,6 +80,7 @@ import org.netbeans.api.debugger.jpda.ObjectVariable; import org.netbeans.api.debugger.jpda.Variable; import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable; import org.netbeans.modules.java.lsp.server.LspSession; +import org.netbeans.modules.java.lsp.server.URITranslator; import org.netbeans.modules.java.lsp.server.debugging.breakpoints.NbBreakpointsRequestHandler; import org.netbeans.modules.java.lsp.server.debugging.attach.NbAttachRequestHandler; import org.netbeans.modules.java.lsp.server.debugging.launch.NbDebugSession; @@ -321,6 +322,7 @@ public final class NbProtocolServer implements IDebugProtocolServer, LspSession. stackFrame.setName(frame.getName()); URI sourceURI = frame.getSourceURI(); if (sourceURI != null) { + sourceURI = URI.create(URITranslator.getDefault().uriToLSP(sourceURI.toString())); Source source = new Source(); String scheme = sourceURI.getScheme(); if (null == scheme || scheme.isEmpty() || "file".equalsIgnoreCase(scheme)) { diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbSourceProvider.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbSourceProvider.java index 9e598bd..35167ee 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbSourceProvider.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbSourceProvider.java @@ -37,6 +37,7 @@ import java.util.logging.Logger; import org.eclipse.lsp4j.debug.Source; import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.modules.java.lsp.server.URITranslator; import org.openide.filesystems.FileObject; /** @@ -96,6 +97,7 @@ public final class NbSourceProvider { public Source getSource(String sourceName, String debuggerURI) { return uriToSource.computeIfAbsent(debuggerURI, uri -> { + uri = URITranslator.getDefault().uriToLSP(uri); Source source = new Source(); source.setName(sourceName); source.setSourceReference(0); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/breakpoints/NbBreakpointsRequestHandler.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/breakpoints/NbBreakpointsRequestHandler.java index cde3ce4..948441f 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/breakpoints/NbBreakpointsRequestHandler.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/breakpoints/NbBreakpointsRequestHandler.java @@ -36,6 +36,7 @@ import org.eclipse.lsp4j.debug.SetExceptionBreakpointsArguments; import org.eclipse.lsp4j.debug.Source; import org.eclipse.lsp4j.debug.SourceBreakpoint; import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode; +import org.netbeans.modules.java.lsp.server.URITranslator; import org.netbeans.modules.java.lsp.server.debugging.DebugAdapterContext; import org.netbeans.modules.java.lsp.server.debugging.utils.ErrorUtilities; @@ -75,6 +76,7 @@ public final class NbBreakpointsRequestHandler { ResponseErrorCode.InvalidParams); return resultFuture; } + sourcePath = URITranslator.getDefault().uriFromLSP(sourcePath); List<Breakpoint> res = new ArrayList<>(); NbBreakpoint[] toAdds = this.convertClientBreakpointsToDebugger(source, sourcePath, arguments.getBreakpoints(), context); // Decode the URI if it comes encoded: --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org For additional commands, e-mail: commits-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists