diff --git a/platform/platform-impl/src/com/intellij/idea/SocketLock.java b/platform/platform-impl/src/com/intellij/idea/SocketLock.java index 5c1f6a797e38..c62da456a672 100644 --- a/platform/platform-impl/src/com/intellij/idea/SocketLock.java +++ b/platform/platform-impl/src/com/intellij/idea/SocketLock.java @@ -38,6 +38,7 @@ import org.jetbrains.io.BuiltInServer; import org.jetbrains.io.MessageDecoder; import java.io.*; +import java.lang.management.ManagementFactory; import java.net.ConnectException; import java.net.Socket; import java.util.Collection; @@ -45,6 +46,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Pattern; /** * @author mike @@ -55,6 +57,7 @@ public final class SocketLock { private static final String PORT_FILE = "port"; private static final String PORT_LOCK_FILE = "port.lock"; private static final String ACTIVATE_COMMAND = "activate "; + private static final String PID_COMMAND = "pid"; private static final String PATHS_EOT_RESPONSE = "---"; private static final String OK_RESPONSE = "ok"; @@ -214,6 +217,9 @@ public final class SocketLock { String response = in.readUTF(); log("read: response=%s", response); if (response.equals(OK_RESPONSE)) { + if (isShutdownCommand(args)) { + printPID(portNumber); + } return ActivateStatus.ACTIVATED; } } @@ -238,6 +244,34 @@ public final class SocketLock { return ActivateStatus.NO_INSTANCE; } + private static void printPID(int port) { + try { + Socket socket = new Socket(NetUtils.getLoopbackAddress(), port); + socket.setSoTimeout(1000); + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") DataOutputStream out = new DataOutputStream(socket.getOutputStream()); + out.writeUTF(PID_COMMAND); + DataInputStream in = new DataInputStream(socket.getInputStream()); + int pid = 0; + while (true) { + try { + String s = in.readUTF(); + if (Pattern.matches("[0-9]+@.*", s)) { + pid = Integer.parseInt(s.substring(0, s.indexOf('@'))); + System.err.println(pid); + } + }catch (IOException e) { + break; + } + } + } + catch (Exception ignore) { + } + } + + private static boolean isShutdownCommand(String[] args) { + return args.length != 0 && Pattern.matches(JetBrainsProtocolHandler.PROTOCOL + "[*]?[a-z0-9A-Z]*/shutdown.*", args[0]); + } + private static String[] checkForJetBrainsProtocolCommand(String[] args) { final String jbUrl = System.getProperty(JetBrainsProtocolHandler.class.getName()); if (jbUrl != null) { @@ -298,6 +332,15 @@ public final class SocketLock { return; } + if (StringUtil.startsWith(command, PID_COMMAND)) { + ByteBuf buffer = context.alloc().ioBuffer(); + ByteBufOutputStream out = new ByteBufOutputStream(buffer); + String name = ManagementFactory.getRuntimeMXBean().getName(); + out.writeUTF(name); + out.close(); + context.writeAndFlush(buffer); + } + if (StringUtil.startsWith(command, ACTIVATE_COMMAND)) { List args = StringUtil.split(command.subSequence(ACTIVATE_COMMAND.length(), command.length()).toString(), "\0"); Consumer> listener = myActivateListener.get(); diff --git a/platform/platform-impl/src/com/intellij/openapi/application/JBProtocolShutdownCommand.java b/platform/platform-impl/src/com/intellij/openapi/application/JBProtocolShutdownCommand.java new file mode 100644 index 000000000000..c463ee907d6e --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/application/JBProtocolShutdownCommand.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed 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 com.intellij.openapi.application; + +import com.intellij.CommonBundle; +import com.intellij.openapi.application.ex.ApplicationManagerEx; +import com.intellij.openapi.ui.MessageDialogBuilder; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.text.StringUtil; + +import java.util.Map; + +/** + * @author Konstantin Bulenkov + */ +public class JBProtocolShutdownCommand extends JBProtocolCommand { + + public JBProtocolShutdownCommand() { + super("shutdown"); + } + + @Override + public void perform(String target, Map parameters) { + if (StringUtil.isEmpty(target)) { + ApplicationManager.getApplication().exit(); + } else { + MessageDialogBuilder.YesNo confirmExitDialog = MessageDialogBuilder.yesNo(ApplicationBundle.message("exit.confirm.title"), target) + .yesText(ApplicationBundle.message("command.exit")).noText( + CommonBundle.message("button.cancel")); + if (confirmExitDialog.show() == Messages.YES) { + ApplicationManagerEx.getApplicationEx().exit(true, true); + } + } + } +} diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index b74c054bfd5d..5c87ca020e05 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -408,6 +408,7 @@ + com.intellij.openapi.editor.actions.FlipCommaIntention diff --git a/platform/util/src/com/intellij/openapi/application/JetBrainsProtocolHandler.java b/platform/util/src/com/intellij/openapi/application/JetBrainsProtocolHandler.java index 5b9549f80643..b4de8218120a 100644 --- a/platform/util/src/com/intellij/openapi/application/JetBrainsProtocolHandler.java +++ b/platform/util/src/com/intellij/openapi/application/JetBrainsProtocolHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,28 +38,33 @@ public class JetBrainsProtocolHandler { public static void processJetBrainsLauncherParameters(String url) { System.setProperty(JetBrainsProtocolHandler.class.getName(), url); url = url.substring(PROTOCOL.length()); - String platformPrefix = url.substring(0, url.indexOf('/')); - url = url.substring(platformPrefix.length() + 1); - String command = url.substring(0, url.indexOf('/')); - url = url.substring(command.length() + 1); - List strings = StringUtil.split(url, "?"); - ourMainParameter = strings.get(0); - ourCommand = command; + List urlParts = StringUtil.split(url, "/"); + if (urlParts.size() < 2) { + System.err.print("Wrong URL: " + PROTOCOL + url); + return; + } + String platformPrefix = urlParts.get(0); + ourCommand = urlParts.get(1); + if (urlParts.size() > 2) { + url = url.substring(platformPrefix.length() + 1 + ourCommand.length() + 1); + List strings = StringUtil.split(url, "?"); + ourMainParameter = strings.get(0); - if (strings.size() > 1) { - List keyValues = StringUtil.split(StringUtil.join(ContainerUtil.subList(strings, 1), "?"), "&"); - for (String keyValue : keyValues) { - if (keyValue.contains("=")) { - int ind = keyValue.indexOf('='); - String key = keyValue.substring(0, ind); - String value = keyValue.substring(ind + 1); - if (REQUIRED_PLUGINS_KEY.equals(key)) { - System.setProperty(key, value); + if (strings.size() > 1) { + List keyValues = StringUtil.split(StringUtil.join(ContainerUtil.subList(strings, 1), "?"), "&"); + for (String keyValue : keyValues) { + if (keyValue.contains("=")) { + int ind = keyValue.indexOf('='); + String key = keyValue.substring(0, ind); + String value = keyValue.substring(ind + 1); + if (REQUIRED_PLUGINS_KEY.equals(key)) { + System.setProperty(key, value); + } else { + ourParameters.put(key, value); + } } else { - ourParameters.put(key, value); + ourParameters.put(keyValue, ""); } - } else { - ourParameters.put(keyValue, ""); } } }