diff --git a/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/bindings/ServerManagementClientImpl.java b/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/bindings/ServerManagementClientImpl.java index 66df3e76b..3e76eb352 100644 --- a/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/bindings/ServerManagementClientImpl.java +++ b/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/bindings/ServerManagementClientImpl.java @@ -123,7 +123,8 @@ public static String getRunStateString(int state) { case ServerManagementAPIConstants.STATE_STOPPING: stateString = "stopping"; break; - + default: + break; } return stateString; } @@ -149,7 +150,8 @@ public static String getPublishStateString(int state) { case ServerManagementAPIConstants.PUBLISH_STATE_UNKNOWN: stateString = "unknown"; break; - + default: + break; } return stateString; } diff --git a/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/cli/ServerManagementCLI.java b/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/cli/ServerManagementCLI.java index 77c1e8692..2a9657845 100644 --- a/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/cli/ServerManagementCLI.java +++ b/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/cli/ServerManagementCLI.java @@ -10,6 +10,7 @@ import java.io.Console; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.Scanner; @@ -113,7 +114,7 @@ protected String getUserInput() { } } if (scanner == null) { - scanner = new Scanner(System.in); + scanner = new Scanner(System.in, StandardCharsets.UTF_8); } return scanner.nextLine(); } diff --git a/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/cli/StandardCommandHandler.java b/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/cli/StandardCommandHandler.java index bf747d3e8..06d0ed2e7 100644 --- a/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/cli/StandardCommandHandler.java +++ b/client/jars/org.jboss.tools.rsp.client.cli/src/main/java/org/jboss/tools/rsp/client/cli/StandardCommandHandler.java @@ -825,11 +825,9 @@ protected ServerHandle findServer(String id, ServerManagementClientLauncher laun protected void printAttr(Attributes attr) { Map map = attr.getAttributes(); - Iterator kit = map.keySet().iterator(); - while (kit.hasNext()) { - String key = kit.next(); - Attribute val = map.get(key); - System.out.println(key); + for (Map.Entry entry : map.entrySet()) { + Attribute val = entry.getValue(); + System.out.println(entry.getKey()); System.out.println(" type=" + val.getType()); System.out.println(" desc=" + val.getDescription()); System.out.println(" defaultVal=" + val.getDefaultVal()); @@ -929,14 +927,12 @@ private static void handleSinglePrompt(WorkflowResponseItem item, HashMap env) { // Convert the combined map into a form that can be used to launch process ArrayList ret = new ArrayList<>(); - Iterator it = original.keySet().iterator(); - String working = null; - while (it.hasNext()) { - working = it.next(); - ret.add(working + "=" + original.get(working)); //$NON-NLS-1$ + for (Map.Entry entry : original.entrySet()) { + ret.add(entry.getKey() + "=" + entry.getValue()); //$NON-NLS-1$ } return ret.toArray(new String[ret.size()]); } diff --git a/framework/bundles/org.jboss.tools.rsp.foundation.core/src/main/java/org/jboss/tools/rsp/foundation/core/launchers/StreamGobbler.java b/framework/bundles/org.jboss.tools.rsp.foundation.core/src/main/java/org/jboss/tools/rsp/foundation/core/launchers/StreamGobbler.java index 7c9b92798..8c3c32be9 100644 --- a/framework/bundles/org.jboss.tools.rsp.foundation.core/src/main/java/org/jboss/tools/rsp/foundation/core/launchers/StreamGobbler.java +++ b/framework/bundles/org.jboss.tools.rsp.foundation.core/src/main/java/org/jboss/tools/rsp/foundation/core/launchers/StreamGobbler.java @@ -12,6 +12,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -45,7 +46,7 @@ private synchronized List getList() { @Override public void run() { try { - InputStreamReader isr = new InputStreamReader(is); + InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8); BufferedReader br = new BufferedReader(isr); String line = null; while (!isCanceled() && (line = br.readLine()) != null) diff --git a/framework/bundles/org.jboss.tools.rsp.foundation.core/src/main/java/org/jboss/tools/rsp/foundation/core/transport/URLTransportCache.java b/framework/bundles/org.jboss.tools.rsp.foundation.core/src/main/java/org/jboss/tools/rsp/foundation/core/transport/URLTransportCache.java index 71712302b..5231e7720 100644 --- a/framework/bundles/org.jboss.tools.rsp.foundation.core/src/main/java/org/jboss/tools/rsp/foundation/core/transport/URLTransportCache.java +++ b/framework/bundles/org.jboss.tools.rsp.foundation.core/src/main/java/org/jboss/tools/rsp/foundation/core/transport/URLTransportCache.java @@ -20,6 +20,7 @@ import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.HttpURLConnection; +import java.nio.charset.StandardCharsets; import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; @@ -473,8 +474,8 @@ private HttpURLConnection getURLConnection(URL url, String user, String pass, in HttpURLConnection.setFollowRedirects(true); if( user != null && pass != null ) { String authString = user + ":" + pass; - byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes()); - String authStringEnc = new String(authEncBytes); + byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes(StandardCharsets.UTF_8)); + String authStringEnc = new String(authEncBytes, StandardCharsets.UTF_8); urlConnection.setRequestProperty("Authorization", "Basic " + authStringEnc); } return urlConnection; diff --git a/framework/bundles/org.jboss.tools.rsp.launching.java/src/main/java/org/jboss/tools/rsp/eclipse/jdt/internal/launching/StandardVMDebugger.java b/framework/bundles/org.jboss.tools.rsp.launching.java/src/main/java/org/jboss/tools/rsp/eclipse/jdt/internal/launching/StandardVMDebugger.java index 87b5d9965..de4afb52e 100644 --- a/framework/bundles/org.jboss.tools.rsp.launching.java/src/main/java/org/jboss/tools/rsp/eclipse/jdt/internal/launching/StandardVMDebugger.java +++ b/framework/bundles/org.jboss.tools.rsp.launching.java/src/main/java/org/jboss/tools/rsp/eclipse/jdt/internal/launching/StandardVMDebugger.java @@ -17,7 +17,6 @@ import java.net.ServerSocket; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -273,11 +272,10 @@ protected String[] prependJREPath(String[] env, IPath jdkpath) { if(env == null){ Map map = NativeEnvironmentUtils.getDefault().getNativeEnvironment(); env = new String[map.size()]; - String var = null; int index = 0; - for(Iterator iter = map.keySet().iterator(); iter.hasNext();) { - var = iter.next(); - String value = map.get(var); + for(Map.Entry entry : map.entrySet()) { + String var = entry.getKey(); + String value = entry.getValue(); if (value == null) { value = ""; //$NON-NLS-1$ } diff --git a/framework/bundles/org.jboss.tools.rsp.launching.java/src/main/java/org/jboss/tools/rsp/internal/launching/java/util/LaunchingSupportUtils.java b/framework/bundles/org.jboss.tools.rsp.launching.java/src/main/java/org/jboss/tools/rsp/internal/launching/java/util/LaunchingSupportUtils.java index b2b41b3c0..6249188cc 100644 --- a/framework/bundles/org.jboss.tools.rsp.launching.java/src/main/java/org/jboss/tools/rsp/internal/launching/java/util/LaunchingSupportUtils.java +++ b/framework/bundles/org.jboss.tools.rsp.launching.java/src/main/java/org/jboss/tools/rsp/internal/launching/java/util/LaunchingSupportUtils.java @@ -12,6 +12,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; +import java.nio.charset.StandardCharsets; import java.net.URL; import java.nio.file.Files; import java.nio.file.StandardCopyOption; @@ -296,7 +297,7 @@ private HashMap parseSysprops(IProcess process, String text) thr HashMap map = new HashMap(); try { DocumentBuilder parser = getParser(); - Document document = parser.parse(new ByteArrayInputStream(text.getBytes())); + Document document = parser.parse(new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8))); Element envs = document.getDocumentElement(); NodeList list = envs.getChildNodes(); int length = list.getLength(); diff --git a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/core/runtime/Path.java b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/core/runtime/Path.java index 857bcac4e..c2fff0d8b 100644 --- a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/core/runtime/Path.java +++ b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/core/runtime/Path.java @@ -588,7 +588,7 @@ public boolean equals(Object obj) { if (!segments[i].equals(targetSegments[i])) return false; //check device last (least likely to differ) - return device == target.device || (device != null && device.equals(target.device)); + return (device == null ? target.device == null : device.equals(target.device)); } /* (Intentionally not included in javadoc) diff --git a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/core/model/RuntimeProcess.java b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/core/model/RuntimeProcess.java index b54d41065..6e414b7b3 100644 --- a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/core/model/RuntimeProcess.java +++ b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/core/model/RuntimeProcess.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. + * Copyright (c) 2000, 2021 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -11,9 +11,15 @@ package org.jboss.tools.rsp.eclipse.debug.core.model; -import java.util.HashMap; +import java.util.Collections; +import java.util.List; import java.util.Map; -import java.util.Map.Entry; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; import org.jboss.tools.rsp.eclipse.core.runtime.IStatus; import org.jboss.tools.rsp.eclipse.core.runtime.Status; @@ -42,14 +48,12 @@ */ public class RuntimeProcess implements IProcess { - private static final int MAX_WAIT_FOR_DEATH_ATTEMPTS = 10; - private static final int TIME_TO_WAIT_FOR_THREAD_DEATH = 500; // ms + private static final int TERMINATION_TIMEOUT = 5000; // ms private static final String RuntimeProcess_Exit_value_not_available_until_process_terminates__1="Exit value not available until process terminates."; private static final String ProcessMonitorJob_0="Process monitor"; private static final String RuntimeProcess_terminate_failed="Terminate failed"; - - + /** * The launch this process is contained in */ @@ -61,7 +65,9 @@ public class RuntimeProcess implements IProcess { private Process fProcess; /** - * This process's exit value + * This process's exit value. + * + * synchronized by this */ private int fExitValue; @@ -69,17 +75,17 @@ public class RuntimeProcess implements IProcess { * The monitor which listens for this runtime process' system process * to terminate. */ - private ProcessMonitorThread fMonitor; + private final ProcessMonitorThread fMonitor; /** * The streams proxy for this process */ - private IStreamsProxy fStreamsProxy; + private final IStreamsProxy fStreamsProxy; /** * The name of the process */ - private String fName; + private final String fName; /** * Whether this process has been terminated @@ -89,12 +95,12 @@ public class RuntimeProcess implements IProcess { /** * Table of client defined attributes */ - private Map fAttributes; + private final Map fAttributes = new ConcurrentHashMap<>(); /** * Whether output from the process should be captured or swallowed */ - private boolean fCaptureOutput = true; + private final boolean fCaptureOutput; /** * Constructs a RuntimeProcess on the given system process @@ -110,22 +116,25 @@ public class RuntimeProcess implements IProcess { public RuntimeProcess(ILaunch launch, Process process, String name, Map attributes) { setLaunch(launch); initializeAttributes(attributes); - fProcess= process; - fName= name; - fTerminated= true; + fProcess = process; + fName = name; + fTerminated = true; try { fExitValue = process.exitValue(); } catch (IllegalThreadStateException e) { - fTerminated= false; + fTerminated = false; } String captureOutput = launch.getAttribute(DebugPluginConstants.ATTR_CAPTURE_OUTPUT); fCaptureOutput = !("false".equals(captureOutput)); //$NON-NLS-1$ - fStreamsProxy= createStreamsProxy(); - fMonitor = new ProcessMonitorThread(this); - fMonitor.start(); + fStreamsProxy = createStreamsProxy(); + fMonitor = new ProcessMonitorThread(); + // Process must be added to launch before starting the monitor thread, + // otherwise the process may terminate and generate notifications before + // they can properly be processed. launch.addProcess(this); + fMonitor.start(); fireCreationEvent(); } @@ -136,9 +145,7 @@ public RuntimeProcess(ILaunch launch, Process process, String name, Map attributes) { if (attributes != null) { - for (Entry entry : attributes.entrySet()) { - setAttribute(entry.getKey(), entry.getValue()); - } + attributes.forEach(this::setAttribute); } } @@ -198,67 +205,91 @@ public synchronized boolean isTerminated() { @Override public void terminate() throws DebugException { if (!isTerminated()) { - if (fStreamsProxy instanceof StreamsProxy) { - ((StreamsProxy)fStreamsProxy).kill(); - } - Process process = getSystemProcess(); - if (process != null) { - process.destroy(); - } - int attempts = 0; - boolean interrupted = false; - while (attempts < MAX_WAIT_FOR_DEATH_ATTEMPTS && !interrupted) { - try { - process = getSystemProcess(); - if (process != null) { - fExitValue = process.exitValue(); // throws exception if process not exited - } + try { + Process process = getSystemProcess(); + if (process == null) { return; - } catch (IllegalThreadStateException ie) { } + + List descendants = Collections.emptyList(); + try { + descendants = process.descendants().collect(Collectors.toList()); + } catch (UnsupportedOperationException e) { + // JVM may not support descendants() + } + + process.destroy(); + descendants.forEach(ProcessHandle::destroy); + try { - Thread.sleep(TIME_TO_WAIT_FOR_THREAD_DEATH); + long waitStart = System.currentTimeMillis(); + if (process.waitFor(TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS)) { + int exitValue = process.exitValue(); + synchronized (this) { + fExitValue = exitValue; + fTerminated = true; + } + if (waitFor(descendants, waitStart)) { + return; + } + } } catch (InterruptedException e) { - interrupted = true; Thread.currentThread().interrupt(); } - attempts++; + } finally { + if (fStreamsProxy instanceof StreamsProxy) { + ((StreamsProxy) fStreamsProxy).kill(); + } } + // clean-up - if (fMonitor != null) { - fMonitor.killThread(); - fMonitor = null; - } + fMonitor.killThread(); IStatus status = new Status(IStatus.ERROR, DebugPluginConstants.DEBUG_CORE_ID, DebugException.TARGET_REQUEST_FAILED, RuntimeProcess_terminate_failed, null); throw new DebugException(status); } } + /** + * Awaits the termination of the processes of the given ProcessHandles. + */ + private boolean waitFor(List descendants, long waitStart) throws InterruptedException { + try { + for (ProcessHandle handle : descendants) { + long remainingTime = TERMINATION_TIMEOUT - (System.currentTimeMillis() - waitStart); + handle.onExit().get(remainingTime, TimeUnit.MILLISECONDS); + } + return true; + } catch (ExecutionException e) { + throw new IllegalStateException(e.getCause()); + } catch (TimeoutException e) { + return false; + } + } + /** * Notification that the system process associated with this process * has terminated. */ protected void terminated() { - if (fStreamsProxy instanceof StreamsProxy) { - ((StreamsProxy)fStreamsProxy).close(); - } - + if (fStreamsProxy instanceof StreamsProxy) { + ((StreamsProxy)fStreamsProxy).close(); + } - // Avoid calling IProcess.exitValue() inside a sync section (Bug 311813). - int exitValue = -1; - boolean running = false; - try { - exitValue = fProcess.exitValue(); - } catch (IllegalThreadStateException ie) { - running = true; - } + // Avoid calling IProcess.exitValue() inside a sync section (Bug 311813). + int exitValue = -1; + boolean running = false; + try { + exitValue = fProcess.exitValue(); + } catch (IllegalThreadStateException ie) { + running = true; + } synchronized (this) { - fTerminated= true; + fTerminated = true; if (!running) { - fExitValue = exitValue; + fExitValue = exitValue; } - fProcess= null; + fProcess = null; } fireTerminateEvent(); } @@ -268,9 +299,9 @@ protected void terminated() { */ @Override public IStreamsProxy getStreamsProxy() { - if (!fCaptureOutput) { - return null; - } + if (!fCaptureOutput) { + return null; + } return fStreamsProxy; } @@ -280,9 +311,9 @@ public IStreamsProxy getStreamsProxy() { * @return streams proxy */ protected IStreamsProxy createStreamsProxy() { - if (!fCaptureOutput) { - return new NullStreamsProxy(getSystemProcess()); - } + if (!fCaptureOutput) { + return new NullStreamsProxy(getSystemProcess()); + } String encoding = getLaunch().getAttribute(DebugPluginConstants.ATTR_CONSOLE_ENCODING); return new StreamsProxy(getSystemProcess(), encoding); } @@ -300,7 +331,6 @@ protected void fireCreationEvent() { * @param event debug event to fire */ protected void fireEvent(DebugEvent event) { - // Changed from DebugPlugin RuntimeProcessEventManager.getDefault() .fireDebugEventSet(new DebugEvent[]{event}); } @@ -324,16 +354,17 @@ protected void fireChangeEvent() { */ @Override public void setAttribute(String key, String value) { - if (fAttributes == null) { - fAttributes = new HashMap(5); - } - Object origVal = fAttributes.get(key); - if (origVal != null && origVal.equals(value)) { - return; //nothing changed. + Objects.requireNonNull(key); + if (value == null) { + if (fAttributes.remove(key) != null) { + fireChangeEvent(); + } + } else { + String origVal = fAttributes.put(key, value); + if (!Objects.equals(origVal, value)) { + fireChangeEvent(); + } } - - fAttributes.put(key, value); - fireChangeEvent(); } /** @@ -341,40 +372,9 @@ public void setAttribute(String key, String value) { */ @Override public String getAttribute(String key) { - if (fAttributes == null) { - return null; - } return fAttributes.get(key); } -// -// /* (non-Javadoc) -// * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) -// */ -// @SuppressWarnings("unchecked") -// @Override -// public T getAdapter(Class adapter) { -// if (adapter.equals(IProcess.class)) { -// return (T) this; -// } -// if (adapter.equals(IDebugTarget.class)) { -// ILaunch launch = getLaunch(); -// IDebugTarget[] targets = launch.getDebugTargets(); -// for (int i = 0; i < targets.length; i++) { -// if (this.equals(targets[i].getProcess())) { -// return (T) targets[i]; -// } -// } -// return null; -// } -// if (adapter.equals(ILaunch.class)) { -// return (T) getLaunch(); -// } -// //CONTEXTLAUNCHING -// if(adapter.equals(ILaunchConfiguration.class)) { -// return (T) getLaunch().getLaunchConfiguration(); -// } -// return super.getAdapter(adapter); -// } + /** * @see IProcess#getExitValue() */ @@ -390,67 +390,37 @@ public synchronized int getExitValue() throws DebugException { * Monitors a system process, waiting for it to terminate, and * then notifies the associated runtime process. */ - class ProcessMonitorThread extends Thread { + private class ProcessMonitorThread extends Thread { /** * Whether the thread has been told to exit. */ - protected boolean fExit; - /** - * The underlying java.lang.Process being monitored. - */ - protected Process fOSProcess; - /** - * The IProcess which will be informed when this - * monitor detects that the underlying process has terminated. - */ - protected RuntimeProcess fRuntimeProcess; - - /** - * The Thread which is monitoring the underlying process. - */ - protected Thread fThread; - - /** - * A lock protecting access to fThread. - */ - private final Object fThreadLock = new Object(); + private volatile boolean fExit; /** * @see Thread#run() */ @Override public void run() { - synchronized (fThreadLock) { - if (fExit) { - return; - } - fThread = Thread.currentThread(); - } - while (fOSProcess != null) { + Process fOSProcess = RuntimeProcess.this.getSystemProcess(); + if (!fExit && fOSProcess != null) { try { fOSProcess.waitFor(); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } finally { - fOSProcess = null; - fRuntimeProcess.terminated(); + RuntimeProcess.this.terminated(); } } - fThread = null; } /** * Creates a new process monitor and starts monitoring the process for * termination. - * - * @param process process to monitor for termination */ - public ProcessMonitorThread(RuntimeProcess process) { + private ProcessMonitorThread() { super(ProcessMonitorJob_0); setDaemon(true); - fRuntimeProcess= process; - fOSProcess= process.getSystemProcess(); } /** @@ -460,14 +430,9 @@ public ProcessMonitorThread(RuntimeProcess process) { * case of an underlying process which has not informed this * monitor of its termination. */ - protected void killThread() { - synchronized (fThreadLock) { - if (fThread == null) { - fExit = true; - } else { - fThread.interrupt(); - } - } + private void killThread() { + fExit = true; + this.interrupt(); } } } diff --git a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/internal/core/NullStreamsProxy.java b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/internal/core/NullStreamsProxy.java index 5676a358b..a828c797e 100644 --- a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/internal/core/NullStreamsProxy.java +++ b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/internal/core/NullStreamsProxy.java @@ -56,7 +56,7 @@ public IStreamMonitor getOutputStreamMonitor() { public void write(String input) throws IOException { } - private class NullStreamMonitor implements IStreamMonitor { + private static class NullStreamMonitor implements IStreamMonitor { private InputStream fStream; public NullStreamMonitor(InputStream stream) { diff --git a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/internal/core/OutputStreamMonitor.java b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/internal/core/OutputStreamMonitor.java index 058c3a00c..26308bff9 100644 --- a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/internal/core/OutputStreamMonitor.java +++ b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/eclipse/debug/internal/core/OutputStreamMonitor.java @@ -14,6 +14,7 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import org.jboss.tools.rsp.eclipse.core.runtime.ISafeRunnable; import org.jboss.tools.rsp.eclipse.core.runtime.ListenerList; @@ -155,7 +156,7 @@ private void read() { if (fEncoding != null) { text = new String(bytes, 0, read, fEncoding); } else { - text = new String(bytes, 0, read); + text = new String(bytes, 0, read, StandardCharsets.UTF_8); } synchronized (this) { if (isBuffered()) { diff --git a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/RuntimeProcessEventManager.java b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/RuntimeProcessEventManager.java index f1f4b8ca6..55dec666f 100644 --- a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/RuntimeProcessEventManager.java +++ b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/RuntimeProcessEventManager.java @@ -16,13 +16,16 @@ public class RuntimeProcessEventManager { - private static RuntimeProcessEventManager instance = new RuntimeProcessEventManager(); - + private static final RuntimeProcessEventManager instance = new RuntimeProcessEventManager(); + private List listeners = new ArrayList<>(); - + public static RuntimeProcessEventManager getDefault() { return instance; } + + private RuntimeProcessEventManager() { + } public synchronized void addListener(IDebugEventSetListener listener) { if (!listeners.contains(listener)) { diff --git a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/memento/JSONMemento.java b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/memento/JSONMemento.java index 2a82614eb..f16136cd7 100644 --- a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/memento/JSONMemento.java +++ b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/memento/JSONMemento.java @@ -18,6 +18,7 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -62,7 +63,7 @@ public static JSONMemento createReadRoot(InputStream in) { public static JSONMemento createReadRoot(InputStream in, boolean encode) { Gson gson = createGson(encode); - try (Reader reader = new InputStreamReader(in)) { + try (Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) { JsonElement rootElement = gson.fromJson(reader, JsonElement.class); return new JSONMemento(rootElement.getAsJsonObject(), ""); } catch (IOException e) { @@ -188,7 +189,7 @@ public void save(OutputStream os) throws IOException { Gson gson = createGson(htmlEncode); JsonElement jsonElement = gson.fromJson(this.jsonObject, JsonElement.class); - try(BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os))) { + try(BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))) { gson.toJson(jsonElement, bw); bw.flush(); } diff --git a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/utils/FileUtil.java b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/utils/FileUtil.java index 9415b4adc..9f1537743 100644 --- a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/utils/FileUtil.java +++ b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/utils/FileUtil.java @@ -12,6 +12,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.Properties; public class FileUtil { @@ -20,7 +21,7 @@ private FileUtil() { } public static String getContents(File aFile) throws IOException { - return new String(getBytesFromFile(aFile)); + return new String(getBytesFromFile(aFile), StandardCharsets.UTF_8); } public static byte[] getBytesFromFile(File file) throws IOException { diff --git a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/utils/NativeEnvironmentUtils.java b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/utils/NativeEnvironmentUtils.java index 6edf60b55..19e487b79 100644 --- a/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/utils/NativeEnvironmentUtils.java +++ b/framework/bundles/org.jboss.tools.rsp.launching/src/main/java/org/jboss/tools/rsp/launching/utils/NativeEnvironmentUtils.java @@ -3,229 +3,67 @@ * All rights reserved. This program is made available under the terms of the * Eclipse Public License v2.0 which accompanies this distribution, and is * available at http://www.eclipse.org/legal/epl-v20.html - * + * * Contributors: Red Hat, Inc. ******************************************************************************/ package org.jboss.tools.rsp.launching.utils; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Properties; public class NativeEnvironmentUtils { private static final NativeEnvironmentUtils instance = new NativeEnvironmentUtils(); public static final NativeEnvironmentUtils getDefault() { return instance; } - - + + private NativeEnvironmentUtils() { + } + /** * The collection of native environment variables on the user's system. Cached * after being computed once as the environment cannot change. */ - private static HashMap fgNativeEnv = null; - private static HashMap fgNativeEnvCasePreserved = null; - + private HashMap fNativeEnv = null; + private HashMap fNativeEnvCasePreserved = null; - /* (non-Javadoc) - * @see org.eclipse.debug.core.ILaunchManager#getNativeEnvironment() - */ public synchronized Map getNativeEnvironment() { - if (fgNativeEnv == null) { + if (fNativeEnv == null) { Map casePreserved = getNativeEnvironmentCasePreserved(); if (OSUtils.isWindows()) { - fgNativeEnv = new HashMap(); + fNativeEnv = new HashMap<>(); for (Entry entry : casePreserved.entrySet()) { - fgNativeEnv.put(entry.getKey().toUpperCase(), entry.getValue()); + fNativeEnv.put(entry.getKey().toUpperCase(), entry.getValue()); } } else { - fgNativeEnv = new HashMap(casePreserved); + fNativeEnv = new HashMap<>(casePreserved); } } - return new HashMap(fgNativeEnv); + return new HashMap<>(fNativeEnv); } - - /* (non-Javadoc) - * @see org.eclipse.debug.core.ILaunchManager#getNativeEnvironmentCasePreserved() - */ public synchronized Map getNativeEnvironmentCasePreserved() { - if (fgNativeEnvCasePreserved == null) { - HashMap tmp = new HashMap<>(); - fillNativeEnvironmentCache(tmp); - fgNativeEnvCasePreserved = tmp; - } - return new HashMap(fgNativeEnvCasePreserved); - } - - private boolean isWin9xME() { - boolean isWin9xME= false; //see bug 50567 - if (OSUtils.isWindows()) { - String osName= System.getProperty("os.name"); //$NON-NLS-1$ - isWin9xME= osName != null && (osName.startsWith("Windows 9") || osName.startsWith("Windows ME")); //$NON-NLS-1$ //$NON-NLS-2$ - } - return isWin9xME; - } - - private String getNativeEnvCommand(boolean isWin9xME, String fileName) { - String nativeCommand= null; - if (OSUtils.isWindows()) { - if (isWin9xME) { - // Win 95, 98, and ME - // SET might not return therefore we pipe into a file - nativeCommand= "command.com /C set > " + fileName; //$NON-NLS-1$ - } else { - // Win NT, 2K, XP - nativeCommand= "cmd.exe /C set"; //$NON-NLS-1$ - } - } else if (!OSUtils.isUnknown()){ - nativeCommand= "env"; //$NON-NLS-1$ - } - return nativeCommand; - } - - private void fillEnvironmentWin9xME(String fileName, Map cache) throws IOException { - //read piped data on Win 95, 98, and ME - Properties p= new Properties(); - File file= new File(fileName); - try(InputStream stream = new BufferedInputStream(new FileInputStream(file))){ - p.load(stream); - if (!file.delete()) { - file.deleteOnExit(); // if delete() fails try again on VM close - } - for (Entry entry : p.entrySet()) { - // Win32's environment variables are case insensitive. Put everything - // to uppercase so that (for example) the "PATH" variable will match - // "pAtH" correctly on Windows. - String key = (String) entry.getKey(); - //no need to cast value - cache.put(key, (String) p.get(key)); - } - } - } - - private void fillEnvironmentStandard(Process process, Map cache) throws IOException { - //read process directly on other platforms - //we need to parse out matching '{' and '}' for function declarations in .bash environments - // pattern is [func name]=() { and we must find the '}' on its own line with no trailing ';' - try (InputStream stream = process.getInputStream(); - InputStreamReader isreader = new InputStreamReader(stream); - BufferedReader reader = new BufferedReader(isreader)) { - String line = reader.readLine(); - String key = null; - String value = null; - String newLine = System.getProperty("line.separator"); //$NON-NLS-1$ - while (line != null) { - int func = line.indexOf("=()"); //$NON-NLS-1$ - if (func > 0) { - key = line.substring(0, func); - // scan until we find the closing '}' with no - // following chars - value = line.substring(func + 1); - while (line != null && !line.equals("}")) { //$NON-NLS-1$ - line = reader.readLine(); - if (line != null) { - value += newLine + line; - } - } - line = reader.readLine(); - } - else { - int separator = line.indexOf('='); - if (separator > 0) { - key = line.substring(0, separator); - value = line.substring(separator + 1); - line = reader.readLine(); - if (line != null) { - // this line has a '=' read ahead to check - // next line for '=', might be broken on - // more than one line - // also if line starts with non-identifier - - // it is remainder of previous variable - while (line.indexOf('=') < 0 || (line.length() > 0 && !Character.isJavaIdentifierStart(line.charAt(0)))) { - value += newLine + line; - line = reader.readLine(); - if (line == null) { - // if next line read is the end of - // the file quit the loop - break; - } - } - } - } - } - if (key != null) { - cache.put(key, value); - key = null; - value = null; - } else { - line = reader.readLine(); - } - } - } - } - /** - * Computes and caches the native system environment variables as a map of - * variable names and values (Strings) in the given map. - *

- * Note that WIN32 system environment preserves - * the case of variable names but is otherwise case insensitive. - * Depending on what you intend to do with the environment, the - * lack of normalization may or may not be create problems. This - * method preserves mixed-case keys using the variable names - * recorded by the OS. - *

- * @param cache the map - * @since 3.1 - */ - private void fillNativeEnvironmentCache(Map cache) { - try { - boolean isWin9xME= isWin9xME(); - File f = File.createTempFile("env_", ".txt"); - f.deleteOnExit(); - String fileName= f.getAbsolutePath(); - String nativeCommand = getNativeEnvCommand(isWin9xME, fileName); - if (nativeCommand == null) { - return; - } - Process process= Runtime.getRuntime().exec(nativeCommand); - if (isWin9xME) { - fillEnvironmentWin9xME(fileName, cache); - } else { - fillEnvironmentStandard(process, cache); - } - } catch (IOException e) { - // Native environment-fetching code failed. - // This can easily happen and is not useful to log. + if (fNativeEnvCasePreserved == null) { + fNativeEnvCasePreserved = new HashMap<>(System.getenv()); } + return new HashMap<>(fNativeEnvCasePreserved); } - public String[] getEnvironment(Map configEnv, boolean appendNativeEnv) { - Map env = new HashMap(); + Map env = new HashMap<>(); if (appendNativeEnv) { env.putAll(NativeEnvironmentUtils.getDefault().getNativeEnvironmentCasePreserved()); } - if( configEnv != null ) { + if (configEnv != null) { env.putAll(configEnv); } - - List strings = new ArrayList(env.size()); - StringBuffer buffer = null; + + List strings = new ArrayList<>(env.size()); for (Entry entry : env.entrySet()) { - buffer = new StringBuffer(entry.getKey()); - buffer.append('=').append(entry.getValue()); - strings.add(buffer.toString()); + strings.add(entry.getKey() + '=' + entry.getValue()); } return strings.toArray(new String[strings.size()]); } diff --git a/framework/bundles/org.jboss.tools.rsp.secure/src/main/java/org/jboss/tools/rsp/secure/model/RSPSecureStorage.java b/framework/bundles/org.jboss.tools.rsp.secure/src/main/java/org/jboss/tools/rsp/secure/model/RSPSecureStorage.java index a5f026976..ee4713b93 100644 --- a/framework/bundles/org.jboss.tools.rsp.secure/src/main/java/org/jboss/tools/rsp/secure/model/RSPSecureStorage.java +++ b/framework/bundles/org.jboss.tools.rsp.secure/src/main/java/org/jboss/tools/rsp/secure/model/RSPSecureStorage.java @@ -12,6 +12,7 @@ import java.io.File; import java.io.IOException; import java.io.StringWriter; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Properties; @@ -53,7 +54,7 @@ public void load() throws CryptoException { try { byte[] encrypted = util.getBytesFromFile(backingFile); byte[] decrypted = util.decrypt(key, encrypted); - byte[] magicBytes = HASH_COMMENT.getBytes(); + byte[] magicBytes = HASH_COMMENT.getBytes(StandardCharsets.UTF_8); if (!startsWith(decrypted, magicBytes)) { throw new CryptoException("Invalid key", null); } @@ -91,7 +92,7 @@ public void save() throws CryptoException { backingFile.getParentFile().mkdirs(); StringWriter sw = new StringWriter(); this.secretData.store(sw, COMMENT); - byte[] raw = sw.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8); + byte[] raw = sw.toString().getBytes(StandardCharsets.UTF_8); byte[] encrypted = util.encrypt(key, raw); util.writeBytesToFile(backingFile, encrypted); } else if (!isInitialized()) { diff --git a/pom.xml b/pom.xml index ab325ddd7..34dbb199c 100644 --- a/pom.xml +++ b/pom.xml @@ -180,6 +180,9 @@ com.github.spotbugs spotbugs-maven-plugin ${spotbugs.version} + + ${maven.multiModuleProjectDirectory}/spotbugs-exclude.xml + diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml new file mode 100644 index 000000000..37805c478 --- /dev/null +++ b/spotbugs-exclude.xml @@ -0,0 +1,10 @@ + + + + + + + +