diff --git a/.idea/libraries/Netty.xml b/.idea/libraries/Netty.xml
index 9d24dbe72c71..3ae05ffb9deb 100644
--- a/.idea/libraries/Netty.xml
+++ b/.idea/libraries/Netty.xml
@@ -4,11 +4,11 @@
-
+
-
+
\ No newline at end of file
diff --git a/lib/annotations/netty/io/netty/channel/annotations.xml b/lib/annotations/netty/io/netty/channel/annotations.xml
index 2c53e34a7c43..13f5c446cf4a 100644
--- a/lib/annotations/netty/io/netty/channel/annotations.xml
+++ b/lib/annotations/netty/io/netty/channel/annotations.xml
@@ -1,4 +1,7 @@
+ -
+
+
-
diff --git a/lib/netty-all-4.1.0.Beta7.jar b/lib/netty-all-4.1.0.Beta7.jar
deleted file mode 100644
index 5b707f12ced3..000000000000
Binary files a/lib/netty-all-4.1.0.Beta7.jar and /dev/null differ
diff --git a/lib/netty-all-4.1.0.Beta8.jar b/lib/netty-all-4.1.0.Beta8.jar
new file mode 100644
index 000000000000..f587b1326f7a
Binary files /dev/null and b/lib/netty-all-4.1.0.Beta8.jar differ
diff --git a/lib/required_for_dist.txt b/lib/required_for_dist.txt
index cec5732200c2..e435b7b06c2b 100644
--- a/lib/required_for_dist.txt
+++ b/lib/required_for_dist.txt
@@ -54,7 +54,7 @@ microba.jar
miglayout-swing.jar
nanoxml-2.2.3.jar
nekohtml-1.9.14.jar
-netty-all-4.1.0.Beta7.jar
+netty-all-4.1.0.Beta8.jar
oromatcher.jar
picocontainer.jar
protobuf-2.5.0.jar
diff --git a/lib/src/netty-all-4.1.0.Beta7-sources.jar b/lib/src/netty-all-4.1.0.Beta8-sources.jar
similarity index 82%
rename from lib/src/netty-all-4.1.0.Beta7-sources.jar
rename to lib/src/netty-all-4.1.0.Beta8-sources.jar
index 3e3d54758a7a..30a39394c5ae 100644
Binary files a/lib/src/netty-all-4.1.0.Beta7-sources.jar and b/lib/src/netty-all-4.1.0.Beta8-sources.jar differ
diff --git a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java
index ffd38062e8c8..0deecd140970 100644
--- a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java
+++ b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java
@@ -97,45 +97,16 @@ public final class NettyUtil {
int maxAttemptCount,
@NotNull Condition stopCondition) throws Throwable {
int attemptCount = 0;
-
if (bootstrap.group() instanceof NioEventLoopGroup) {
- while (true) {
- ChannelFuture future = bootstrap.connect(remoteAddress).awaitUninterruptibly();
- if (future.isSuccess()) {
- return future.channel();
- }
- else if (stopCondition.value(null) || (promise != null && promise.getState() == Promise.State.REJECTED)) {
- return null;
- }
- else if (maxAttemptCount == -1) {
- //noinspection BusyWait
- Thread.sleep(300);
- attemptCount++;
- }
- else if (++attemptCount < maxAttemptCount) {
- //noinspection BusyWait
- Thread.sleep(attemptCount * MIN_START_TIME);
- }
- else {
- @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
- Throwable cause = future.cause();
- if (promise != null) {
- if (cause == null) {
- promise.setError("Cannot connect: unknown error");
- }
- else {
- promise.setError(cause);
- }
- }
- return null;
- }
- }
+ return connectNio(bootstrap, remoteAddress, promise, maxAttemptCount, stopCondition, attemptCount);
}
+ bootstrap.validate();
+
Socket socket;
while (true) {
try {
- //noinspection SocketOpenedButNotSafelyClosed
+ //noinspection IOResourceOpenedButNotSafelyClosed,SocketOpenedButNotSafelyClosed
socket = new Socket(remoteAddress.getAddress(), remoteAddress.getPort());
break;
}
@@ -144,13 +115,15 @@ public final class NettyUtil {
return null;
}
else if (maxAttemptCount == -1) {
- //noinspection BusyWait
- Thread.sleep(300);
+ if (sleep(promise, 300)) {
+ return null;
+ }
attemptCount++;
}
else if (++attemptCount < maxAttemptCount) {
- //noinspection BusyWait
- Thread.sleep(attemptCount * MIN_START_TIME);
+ if (sleep(promise, attemptCount * MIN_START_TIME)) {
+ return null;
+ }
}
else {
if (promise != null) {
@@ -160,11 +133,71 @@ public final class NettyUtil {
}
}
}
+
OioSocketChannel channel = new OioSocketChannel(socket);
BootstrapUtil.initAndRegister(channel, bootstrap).sync();
return channel;
}
+ @Nullable
+ private static Channel connectNio(@NotNull Bootstrap bootstrap,
+ @NotNull InetSocketAddress remoteAddress,
+ @Nullable AsyncPromise> promise,
+ int maxAttemptCount,
+ @NotNull Condition stopCondition,
+ int attemptCount) {
+ while (true) {
+ ChannelFuture future = bootstrap.connect(remoteAddress).awaitUninterruptibly();
+ if (future.isSuccess()) {
+ if (!future.channel().isOpen()) {
+ continue;
+ }
+ return future.channel();
+ }
+ else if (stopCondition.value(null) || (promise != null && promise.getState() == Promise.State.REJECTED)) {
+ return null;
+ }
+ else if (maxAttemptCount == -1) {
+ if (sleep(promise, 300)) {
+ return null;
+ }
+ attemptCount++;
+ }
+ else if (++attemptCount < maxAttemptCount) {
+ if (sleep(promise, attemptCount * MIN_START_TIME)) {
+ return null;
+ }
+ }
+ else {
+ @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+ Throwable cause = future.cause();
+ if (promise != null) {
+ if (cause == null) {
+ promise.setError("Cannot connect: unknown error");
+ }
+ else {
+ promise.setError(cause);
+ }
+ }
+ return null;
+ }
+ }
+ }
+
+ private static boolean sleep(@Nullable AsyncPromise> promise, int time) {
+ try {
+ //noinspection BusyWait
+ Thread.sleep(time);
+ }
+ catch (InterruptedException ignored) {
+ if (promise != null) {
+ promise.setError("Interrupted");
+ }
+ return true;
+ }
+ return false;
+ }
+
private static boolean isAsWarning(@NotNull Throwable throwable) {
String message = throwable.getMessage();
if (message == null) {
diff --git a/platform/script-debugger/backend/src/util.kt b/platform/script-debugger/backend/src/util.kt
index 7feee87e8513..7fe57aa2c8e0 100644
--- a/platform/script-debugger/backend/src/util.kt
+++ b/platform/script-debugger/backend/src/util.kt
@@ -20,8 +20,10 @@ import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.CharsetToolkit
import io.netty.buffer.ByteBuf
+import io.netty.channel.Channel
import org.jetbrains.annotations.PropertyKey
import org.jetbrains.io.JsonReaderEx
+import org.jetbrains.io.addListener
import java.io.File
import java.io.FileOutputStream
import java.nio.CharBuffer
@@ -33,6 +35,8 @@ internal class LogEntry(val message: Any, val marker: String) {
}
class MessagingLogger internal constructor(private val queue: ConcurrentLinkedQueue) {
+ internal @Volatile var closed = false
+
fun add(inMessage: CharSequence, marker: String = "IN") {
queue.add(LogEntry(inMessage, marker))
}
@@ -40,9 +44,24 @@ class MessagingLogger internal constructor(private val queue: ConcurrentLinkedQu
fun add(outMessage: ByteBuf, marker: String = "OUT") {
queue.add(LogEntry(outMessage.copy(), marker))
}
+
+ fun close() {
+ closed = true
+ }
+
+ fun closeOnChannelClose(channel: Channel) {
+ channel.closeFuture().addListener {
+ try {
+ add("\"Closed\"", "Channel")
+ }
+ finally {
+ close()
+ }
+ }
+ }
}
-fun createDebugLogger(@PropertyKey(resourceBundle = Registry.REGISTRY_BUNDLE) key: String, vm: AttachStateManager): MessagingLogger? {
+fun createDebugLogger(@PropertyKey(resourceBundle = Registry.REGISTRY_BUNDLE) key: String): MessagingLogger? {
val debugFile = Registry.stringValue(key)
if (debugFile.isNullOrEmpty()) {
return null
@@ -60,42 +79,44 @@ fun createDebugLogger(@PropertyKey(resourceBundle = Registry.REGISTRY_BUNDLE) ke
val dateFormatter = SimpleDateFormat("HH.mm.ss,SSS")
- o@ do {
- while (true) {
- val entry = queue.poll() ?: continue@o
+ while (true) {
+ val entry = queue.poll() ?: if (logger.closed) {
+ break
+ }
+ else {
+ continue
+ }
- writer.write("""{"timestamp": "${dateFormatter.format(entry.time)}", """)
- val message = entry.message
- when (message) {
- is CharSequence -> {
- writer.write("\"${entry.marker}\": ")
- writer.flush()
+ writer.write("""{"timestamp": "${dateFormatter.format(entry.time)}", """)
+ val message = entry.message
+ when (message) {
+ is CharSequence -> {
+ writer.write("\"${entry.marker}\": ")
+ writer.flush()
- if (message is JsonReaderEx.CharSequenceBackedByChars) {
- fileChannel.write(message.byteBuffer)
- }
- else {
- fileChannel.write(CharsetToolkit.UTF8_CHARSET.encode(CharBuffer.wrap(message)))
- }
-
- writer.write("},\n")
- writer.flush()
+ if (message is JsonReaderEx.CharSequenceBackedByChars) {
+ fileChannel.write(message.byteBuffer)
}
- is ByteBuf -> {
- writer.write("\"${entry.marker}\": ")
- writer.flush()
-
- message.getBytes(message.readerIndex(), out, message.readableBytes())
- message.release()
-
- writer.write("},\n")
- writer.flush()
+ else {
+ fileChannel.write(CharsetToolkit.UTF8_CHARSET.encode(CharBuffer.wrap(message)))
}
- else -> throw RuntimeException("Unknown message type")
+
+ writer.write("},\n")
+ writer.flush()
}
+ is ByteBuf -> {
+ writer.write("\"${entry.marker}\": ")
+ writer.flush()
+
+ message.getBytes(message.readerIndex(), out, message.readableBytes())
+ message.release()
+
+ writer.write("},\n")
+ writer.flush()
+ }
+ else -> throw RuntimeException("Unknown message type")
}
}
- while (vm.isAttached)
writer.write("]")
out.close()
}
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ScopeVariablesGroup.kt b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ScopeVariablesGroup.kt
index b8dd49b3e64d..1a3fb4226ae0 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ScopeVariablesGroup.kt
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ScopeVariablesGroup.kt
@@ -43,8 +43,12 @@ class ScopeVariablesGroup(val scope: Scope, parentContext: VariableContext, call
promise
.done(node) {
callFrame.receiverVariable
- .done(node) { node.addChildren(if (it == null) XValueChildrenList.EMPTY else XValueChildrenList.singleton(VariableView(it, context)), true) }
- .rejected(node) { node.addChildren(XValueChildrenList.EMPTY, true) }
+ .done(node) {
+ node.addChildren(if (it == null) XValueChildrenList.EMPTY else XValueChildrenList.singleton(VariableView(it, context)), true)
+ }
+ .rejected(node) {
+ node.addChildren(XValueChildrenList.EMPTY, true)
+ }
}
}
}
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.kt b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.kt
index 62eac1928be2..55464c82ff98 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.kt
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.kt
@@ -47,7 +47,14 @@ fun processScopeVariables(scope: Scope,
context: VariableContext,
isLast: Boolean) = processVariables(context, scope.variablesHost.get(), node, { memberFilter, variables ->
val additionalVariables = memberFilter.additionalVariables
- val properties = ArrayList(variables.size + additionalVariables.size)
+
+ val exceptionValue = context.viewSupport.vm?.suspendContextManager?.context?.exceptionData?.exceptionValue
+ val properties = ArrayList(variables.size + additionalVariables.size + (if (exceptionValue == null) 0 else 1))
+
+ exceptionValue?.let {
+ properties.add(VariableImpl("Exception", it))
+ }
+
val functions = SmartList()
for (variable in variables) {
if (memberFilter.isMemberVisible(variable)) {