1.1 --- a/java.preprocessorbridge/nbproject/project.xml Wed Apr 06 13:12:27 2016 +0200
1.2 +++ b/java.preprocessorbridge/nbproject/project.xml Thu Apr 07 14:00:03 2016 +0200
1.3 @@ -81,6 +81,7 @@
1.4 <friend>org.netbeans.modules.scala.editor</friend>
1.5 <friend>org.netbeans.modules.web.core.syntax</friend>
1.6 <friend>org.netbeans.modules.whitelist</friend>
1.7 + <friend>org.netbeans.modules.jshell.support</friend>
1.8 <package>org.netbeans.modules.java.preprocessorbridge.api</package>
1.9 <package>org.netbeans.modules.java.preprocessorbridge.spi</package>
1.10 </friend-packages>
2.1 --- a/jshell.support/nbproject/project.xml Wed Apr 06 13:12:27 2016 +0200
2.2 +++ b/jshell.support/nbproject/project.xml Thu Apr 07 14:00:03 2016 +0200
2.3 @@ -279,6 +279,14 @@
2.4 </run-dependency>
2.5 </dependency>
2.6 <dependency>
2.7 + <code-name-base>org.netbeans.modules.java.preprocessorbridge</code-name-base>
2.8 + <build-prerequisite/>
2.9 + <compile-dependency/>
2.10 + <run-dependency>
2.11 + <specification-version>1.39</specification-version>
2.12 + </run-dependency>
2.13 + </dependency>
2.14 + <dependency>
2.15 <code-name-base>org.netbeans.modules.java.project</code-name-base>
2.16 <build-prerequisite/>
2.17 <compile-dependency/>
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/editor/CompletionFilter.java Thu Apr 07 14:00:03 2016 +0200
3.3 @@ -0,0 +1,224 @@
3.4 +/*
3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3.6 + *
3.7 + * Copyright 2016 Oracle and/or its affiliates. All rights reserved.
3.8 + *
3.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
3.10 + * Other names may be trademarks of their respective owners.
3.11 + *
3.12 + * The contents of this file are subject to the terms of either the GNU
3.13 + * General Public License Version 2 only ("GPL") or the Common
3.14 + * Development and Distribution License("CDDL") (collectively, the
3.15 + * "License"). You may not use this file except in compliance with the
3.16 + * License. You can obtain a copy of the License at
3.17 + * http://www.netbeans.org/cddl-gplv2.html
3.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
3.19 + * specific language governing permissions and limitations under the
3.20 + * License. When distributing the software, include this License Header
3.21 + * Notice in each file and include the License file at
3.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
3.23 + * particular file as subject to the "Classpath" exception as provided
3.24 + * by Oracle in the GPL Version 2 section of the License file that
3.25 + * accompanied this code. If applicable, add the following below the
3.26 + * License Header, with the fields enclosed by brackets [] replaced by
3.27 + * your own identifying information:
3.28 + * "Portions Copyrighted [year] [name of copyright owner]"
3.29 + *
3.30 + * If you wish your version of this file to be governed by only the CDDL
3.31 + * or only the GPL Version 2, indicate your decision by adding
3.32 + * "[Contributor] elects to include this software in this distribution
3.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
3.34 + * single choice of license, a recipient has the option to distribute
3.35 + * your version of this file under either the CDDL, the GPL Version 2 or
3.36 + * to extend the choice of license to its licensees as provided above.
3.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
3.38 + * Version 2 license, then the option applies only if the new code is
3.39 + * made subject to such option by the copyright holder.
3.40 + *
3.41 + * Contributor(s):
3.42 + *
3.43 + * Portions Copyrighted 2016 Sun Microsystems, Inc.
3.44 + */
3.45 +package org.netbeans.modules.jshell.editor;
3.46 +
3.47 +import com.sun.source.doctree.DocCommentTree;
3.48 +import com.sun.source.doctree.DocTree;
3.49 +import com.sun.source.tree.CatchTree;
3.50 +import com.sun.source.tree.ClassTree;
3.51 +import com.sun.source.tree.CompilationUnitTree;
3.52 +import com.sun.source.tree.MethodTree;
3.53 +import com.sun.source.tree.Scope;
3.54 +import com.sun.source.tree.Tree;
3.55 +import com.sun.source.util.DocSourcePositions;
3.56 +import com.sun.source.util.DocTreePath;
3.57 +import com.sun.source.util.DocTrees;
3.58 +import com.sun.source.util.TreePath;
3.59 +import com.sun.source.util.Trees;
3.60 +import java.io.IOException;
3.61 +import java.text.BreakIterator;
3.62 +import java.util.List;
3.63 +import javax.lang.model.element.AnnotationMirror;
3.64 +import javax.lang.model.element.AnnotationValue;
3.65 +import javax.lang.model.element.Element;
3.66 +import javax.lang.model.element.ExecutableElement;
3.67 +import javax.lang.model.element.TypeElement;
3.68 +import javax.lang.model.type.DeclaredType;
3.69 +import javax.lang.model.type.ErrorType;
3.70 +import javax.lang.model.type.TypeMirror;
3.71 +import javax.tools.Diagnostic;
3.72 +import javax.tools.FileObject;
3.73 +
3.74 +/**
3.75 + * Filters out REPL generated classes from code completion.
3.76 + * @author sdedic
3.77 + */
3.78 +final class CompletionFilter extends DocTrees {
3.79 +
3.80 + public CompletionFilter(Trees delegate) {
3.81 + this.delegate = (DocTrees)delegate;
3.82 + }
3.83 +
3.84 + @Override
3.85 + public BreakIterator getBreakIterator() {
3.86 + return delegate.getBreakIterator();
3.87 + }
3.88 +
3.89 + @Override
3.90 + public DocCommentTree getDocCommentTree(TreePath tp) {
3.91 + return delegate.getDocCommentTree(tp);
3.92 + }
3.93 +
3.94 + @Override
3.95 + public DocCommentTree getDocCommentTree(Element elmnt) {
3.96 + return delegate.getDocCommentTree(elmnt);
3.97 + }
3.98 +
3.99 + @Override
3.100 + public DocCommentTree getDocCommentTree(FileObject fo) {
3.101 + return delegate.getDocCommentTree(fo);
3.102 + }
3.103 +
3.104 + @Override
3.105 + public DocCommentTree getDocCommentTree(Element elmnt, String string) throws IOException {
3.106 + return delegate.getDocCommentTree(elmnt, string);
3.107 + }
3.108 +
3.109 + @Override
3.110 + public Element getElement(DocTreePath dtp) {
3.111 + return delegate.getElement(dtp);
3.112 + }
3.113 +
3.114 + @Override
3.115 + public List<DocTree> getFirstSentence(List<? extends DocTree> list) {
3.116 + return delegate.getFirstSentence(list);
3.117 + }
3.118 +
3.119 + @Override
3.120 + public void printMessage(Diagnostic.Kind kind, CharSequence cs, DocTree dt, DocCommentTree dct, CompilationUnitTree cut) {
3.121 + delegate.printMessage(kind, cs, dt, dct, cut);
3.122 + }
3.123 +
3.124 + @Override
3.125 + public void setBreakIterator(BreakIterator bi) {
3.126 + delegate.setBreakIterator(bi);
3.127 + }
3.128 +
3.129 + @Override
3.130 + public DocSourcePositions getSourcePositions() {
3.131 + return delegate.getSourcePositions();
3.132 + }
3.133 +
3.134 + @Override
3.135 + public Tree getTree(Element elmnt) {
3.136 + return delegate.getTree(elmnt);
3.137 + }
3.138 +
3.139 + @Override
3.140 + public ClassTree getTree(TypeElement te) {
3.141 + return delegate.getTree(te);
3.142 + }
3.143 +
3.144 + @Override
3.145 + public MethodTree getTree(ExecutableElement ee) {
3.146 + return delegate.getTree(ee);
3.147 + }
3.148 +
3.149 + @Override
3.150 + public Tree getTree(Element elmnt, AnnotationMirror am) {
3.151 + return delegate.getTree(elmnt, am);
3.152 + }
3.153 +
3.154 + @Override
3.155 + public Tree getTree(Element elmnt, AnnotationMirror am, AnnotationValue av) {
3.156 + return delegate.getTree(elmnt, am, av);
3.157 + }
3.158 +
3.159 + @Override
3.160 + public TreePath getPath(CompilationUnitTree cut, Tree tree) {
3.161 + return delegate.getPath(cut, tree);
3.162 + }
3.163 +
3.164 + @Override
3.165 + public TreePath getPath(Element elmnt) {
3.166 + return delegate.getPath(elmnt);
3.167 + }
3.168 +
3.169 + @Override
3.170 + public TreePath getPath(Element elmnt, AnnotationMirror am) {
3.171 + return delegate.getPath(elmnt, am);
3.172 + }
3.173 +
3.174 + @Override
3.175 + public TreePath getPath(Element elmnt, AnnotationMirror am, AnnotationValue av) {
3.176 + return delegate.getPath(elmnt, am, av);
3.177 + }
3.178 +
3.179 + @Override
3.180 + public Element getElement(TreePath tp) {
3.181 + return delegate.getElement(tp);
3.182 + }
3.183 +
3.184 + @Override
3.185 + public TypeMirror getTypeMirror(TreePath tp) {
3.186 + return delegate.getTypeMirror(tp);
3.187 + }
3.188 +
3.189 + @Override
3.190 + public Scope getScope(TreePath tp) {
3.191 + return delegate.getScope(tp);
3.192 + }
3.193 +
3.194 + @Override
3.195 + public String getDocComment(TreePath tp) {
3.196 + return delegate.getDocComment(tp);
3.197 + }
3.198 +
3.199 + @Override
3.200 + public boolean isAccessible(Scope scope, TypeElement te) {
3.201 + if (te.getQualifiedName().toString().startsWith("REPL.")) {
3.202 + return false;
3.203 + }
3.204 + return delegate.isAccessible(scope, te);
3.205 + }
3.206 +
3.207 + @Override
3.208 + public boolean isAccessible(Scope scope, Element elmnt, DeclaredType dt) {
3.209 + return delegate.isAccessible(scope, elmnt, dt);
3.210 + }
3.211 +
3.212 + @Override
3.213 + public TypeMirror getOriginalType(ErrorType et) {
3.214 + return delegate.getOriginalType(et);
3.215 + }
3.216 +
3.217 + @Override
3.218 + public void printMessage(Diagnostic.Kind kind, CharSequence cs, Tree tree, CompilationUnitTree cut) {
3.219 + delegate.printMessage(kind, cs, tree, cut);
3.220 + }
3.221 +
3.222 + @Override
3.223 + public TypeMirror getLub(CatchTree ct) {
3.224 + return delegate.getLub(ct);
3.225 + }
3.226 + private DocTrees delegate;
3.227 +}
4.1 --- a/jshell.support/src/org/netbeans/modules/jshell/editor/ConsoleEditor.java Wed Apr 06 13:12:27 2016 +0200
4.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/editor/ConsoleEditor.java Thu Apr 07 14:00:03 2016 +0200
4.3 @@ -41,6 +41,7 @@
4.4 */
4.5 package org.netbeans.modules.jshell.editor;
4.6
4.7 +import com.sun.source.util.Trees;
4.8 import java.awt.Point;
4.9 import java.awt.Rectangle;
4.10 import java.awt.event.ActionEvent;
4.11 @@ -61,6 +62,7 @@
4.12 import javax.swing.text.Position;
4.13 import org.netbeans.api.editor.document.LineDocument;
4.14 import org.netbeans.api.editor.document.LineDocumentUtils;
4.15 +import org.netbeans.modules.java.preprocessorbridge.spi.WrapperFactory;
4.16 import org.netbeans.modules.jshell.env.JShellEnvironment;
4.17 import org.netbeans.modules.jshell.env.ShellEvent;
4.18 import org.netbeans.modules.jshell.env.ShellListener;
4.19 @@ -210,6 +212,14 @@
4.20 });
4.21
4.22 (pane = getEditorPane()).setNavigationFilter(new NavFilter());
4.23 +
4.24 + d.putProperty(WrapperFactory.class, new WrapperFactory() {
4.25 + @Override
4.26 + public Trees wrapTrees(Trees trees) {
4.27 + return new CompletionFilter(trees);
4.28 + }
4.29 +
4.30 + });
4.31 SwingUtilities.invokeLater(this::updateHourglass);
4.32 }
4.33
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/j2se/JShellStartupExtender.java Thu Apr 07 14:00:03 2016 +0200
5.3 @@ -0,0 +1,106 @@
5.4 +/*
5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
5.6 + *
5.7 + * Copyright 2016 Oracle and/or its affiliates. All rights reserved.
5.8 + *
5.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
5.10 + * Other names may be trademarks of their respective owners.
5.11 + *
5.12 + * The contents of this file are subject to the terms of either the GNU
5.13 + * General Public License Version 2 only ("GPL") or the Common
5.14 + * Development and Distribution License("CDDL") (collectively, the
5.15 + * "License"). You may not use this file except in compliance with the
5.16 + * License. You can obtain a copy of the License at
5.17 + * http://www.netbeans.org/cddl-gplv2.html
5.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
5.19 + * specific language governing permissions and limitations under the
5.20 + * License. When distributing the software, include this License Header
5.21 + * Notice in each file and include the License file at
5.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
5.23 + * particular file as subject to the "Classpath" exception as provided
5.24 + * by Oracle in the GPL Version 2 section of the License file that
5.25 + * accompanied this code. If applicable, add the following below the
5.26 + * License Header, with the fields enclosed by brackets [] replaced by
5.27 + * your own identifying information:
5.28 + * "Portions Copyrighted [year] [name of copyright owner]"
5.29 + *
5.30 + * If you wish your version of this file to be governed by only the CDDL
5.31 + * or only the GPL Version 2, indicate your decision by adding
5.32 + * "[Contributor] elects to include this software in this distribution
5.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
5.34 + * single choice of license, a recipient has the option to distribute
5.35 + * your version of this file under either the CDDL, the GPL Version 2 or
5.36 + * to extend the choice of license to its licensees as provided above.
5.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
5.38 + * Version 2 license, then the option applies only if the new code is
5.39 + * made subject to such option by the copyright holder.
5.40 + *
5.41 + * Contributor(s):
5.42 + *
5.43 + * Portions Copyrighted 2016 Sun Microsystems, Inc.
5.44 + */
5.45 +package org.netbeans.modules.jshell.j2se;
5.46 +
5.47 +import java.io.IOException;
5.48 +import java.net.InetSocketAddress;
5.49 +import java.util.Collections;
5.50 +import java.util.EnumSet;
5.51 +import java.util.List;
5.52 +import java.util.logging.Level;
5.53 +import java.util.logging.Logger;
5.54 +import org.netbeans.api.extexecution.startup.StartupExtender.StartMode;
5.55 +import org.netbeans.api.project.Project;
5.56 +import org.netbeans.modules.java.j2seproject.api.J2SEPropertyEvaluator;
5.57 +import org.netbeans.modules.jshell.launch.ShellAgent;
5.58 +import org.netbeans.modules.jshell.launch.ShellLaunchManager;
5.59 +import org.netbeans.modules.jshell.project.LaunchedProjectOpener;
5.60 +import org.netbeans.modules.jshell.project.ProjectUtils;
5.61 +import org.netbeans.spi.extexecution.startup.StartupExtenderImplementation;
5.62 +import org.openide.util.Lookup;
5.63 +
5.64 +/**
5.65 + * Hooks onto the J2SE project startup, and injects JShell agent as java agent.
5.66 + *
5.67 + * @author sdedic
5.68 + */
5.69 +@StartupExtenderImplementation.Registration(displayName = "Java Shell", startMode = {
5.70 + StartMode.DEBUG,
5.71 + StartMode.NORMAL,
5.72 +})
5.73 +public class JShellStartupExtender implements StartupExtenderImplementation {
5.74 + private static final Logger LOG = Logger.getLogger(JShellStartupExtender.class.getName());
5.75 +
5.76 + @Override
5.77 + public List<String> getArguments(Lookup context, StartMode mode) {
5.78 + LaunchedProjectOpener.init();
5.79 +
5.80 + Project p = context.lookup(Project.class);
5.81 + if (p == null) {
5.82 + return Collections.emptyList();
5.83 + }
5.84 +
5.85 + LOG.log(Level.FINE, "Augmenting {0} of project {1}", new Object[] { mode, p });
5.86 +
5.87 + InetSocketAddress isa;
5.88 + ShellAgent agent;
5.89 + // first check that the project has JShell enabled:
5.90 + if (!ProjectUtils.isJShellRunEnabled(p)) {
5.91 + LOG.log(Level.FINE, "Request for agent: Project {0} does not enable Java Shell.", p);
5.92 + return Collections.emptyList();
5.93 + }
5.94 + try {
5.95 + agent = ShellLaunchManager.getInstance().openForProject(p,
5.96 + mode == StartMode.DEBUG || mode == StartMode.TEST_DEBUG);
5.97 + isa = agent.getHandshakeAddress();
5.98 + } catch (IOException ex) {
5.99 + LOG.log(Level.INFO, "Could not obtain handshake address and key: ", ex);
5.100 + return Collections.emptyList();
5.101 + }
5.102 + LOG.log(Level.FINE, "Connect address is: {0}:{1}", new Object[] { isa.getHostString(), isa.getPort() });
5.103 +
5.104 + J2SEPropertyEvaluator prjEval = p.getLookup().lookup(J2SEPropertyEvaluator.class);
5.105 + List<String> args = ShellLaunchManager.buildLocalJVMAgentArgs(agent, prjEval.evaluator()::getProperty);
5.106 + LOG.log(Level.FINE, "Final args: {0}", args);
5.107 + return args;
5.108 + }
5.109 +}
6.1 --- a/jshell.support/src/org/netbeans/modules/jshell/j2se/LaunchAntListener.java Wed Apr 06 13:12:27 2016 +0200
6.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/j2se/LaunchAntListener.java Thu Apr 07 14:00:03 2016 +0200
6.3 @@ -75,7 +75,8 @@
6.4 "debug-test-main-nb", // NOI18N
6.5 "debug-test-with-main", // NOI18N
6.6 "debug-single", // NOI18N
6.7 - "debug" // NOI18N
6.8 + "debug", // NOI18N
6.9 + "run",
6.10 };
6.11
6.12 private ShellLaunchManager mgr;
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/launch/DebugExecutionEnvironment.java Thu Apr 07 14:00:03 2016 +0200
7.3 @@ -0,0 +1,146 @@
7.4 +/*
7.5 + * To change this license header, choose License Headers in Project Properties.
7.6 + * To change this template file, choose Tools | Templates
7.7 + * and open the template in the editor.
7.8 + */
7.9 +package org.netbeans.modules.jshell.launch;
7.10 +
7.11 +import com.sun.jdi.ObjectReference;
7.12 +import com.sun.jdi.VirtualMachine;
7.13 +import java.io.IOException;
7.14 +import java.io.InputStream;
7.15 +import java.io.OutputStream;
7.16 +import java.util.function.UnaryOperator;
7.17 +import jdk.jshell.JDIRemoteAgent;
7.18 +import org.openide.awt.StatusDisplayer;
7.19 +import org.openide.util.NbBundle;
7.20 +
7.21 +/**
7.22 + *
7.23 + * @author sdedic
7.24 + */
7.25 +public class DebugExecutionEnvironment extends JDIRemoteAgent implements RemoteJShellAccessor, ShellLaunchListener {
7.26 + private boolean added;
7.27 + private volatile JShellConnection shellConnection;
7.28 + private boolean closed;
7.29 + final ShellAgent agent;
7.30 +
7.31 + public DebugExecutionEnvironment(ShellAgent agent) {
7.32 + super(UnaryOperator.identity());
7.33 + this.agent = agent;
7.34 + }
7.35 +
7.36 + public JShellConnection getOpenedConnection() {
7.37 + synchronized (this) {
7.38 + return shellConnection;
7.39 + }
7.40 + }
7.41 +
7.42 + public ShellAgent getAgent() {
7.43 + return agent;
7.44 + }
7.45 +
7.46 + @NbBundle.Messages({
7.47 + "MSG_AgentConnectionBroken2=Connection to Java Shell agent broken. Please re-run the project.",
7.48 + "# {0} - error message",
7.49 + "MSG_ErrorConnectingToAgent=Error connecting to Java Shell agent: {0}"
7.50 + })
7.51 + private JShellConnection getConnection(boolean dontConnect) throws IOException {
7.52 + synchronized (this) {
7.53 + if (closed || (dontConnect && shellConnection == null)) {
7.54 + throw new IOException(Bundle.MSG_AgentConnectionBroken2());
7.55 + }
7.56 + if (shellConnection != null) {
7.57 + return shellConnection;
7.58 + }
7.59 + }
7.60 + try {
7.61 + JShellConnection x = agent.createConnection();
7.62 + synchronized (this) {
7.63 + if (!added) {
7.64 + ShellLaunchManager.getInstance().addLaunchListener(this);
7.65 + added = true;
7.66 + }
7.67 + return this.shellConnection = x;
7.68 + }
7.69 + } catch (IOException ex) {
7.70 + StatusDisplayer.getDefault().setStatusText(Bundle.MSG_ErrorConnectingToAgent(ex.getLocalizedMessage()), 100);
7.71 + throw ex;
7.72 + }
7.73 + }
7.74 +
7.75 + @Override
7.76 + public OutputStream getCommandStream() throws IOException {
7.77 + return getConnection(true).getAgentInput();
7.78 + }
7.79 +
7.80 + @Override
7.81 + public InputStream getResponseStream() throws IOException {
7.82 + return getConnection(true).getAgentOutput();
7.83 + }
7.84 +
7.85 + @Override
7.86 + public synchronized void closeStreams() {
7.87 + if (shellConnection == null) {
7.88 + return;
7.89 + }
7.90 + try {
7.91 + OutputStream os = shellConnection.getAgentInput();
7.92 + os.close();
7.93 + } catch (IOException ex) {
7.94 + }
7.95 + try {
7.96 + InputStream is = shellConnection.getAgentOutput();
7.97 + is.close();
7.98 + } catch (IOException ex) {
7.99 + }
7.100 + requestShutdown();
7.101 + }
7.102 +
7.103 + @Override
7.104 + protected ObjectReference getAgentObjectReference() {
7.105 + return shellConnection.getAgentHandle();
7.106 + }
7.107 +
7.108 + @Override
7.109 + protected VirtualMachine acquireVirtualMachine() throws IOException {
7.110 + return getConnection(false).getVirtualMachine();
7.111 + }
7.112 +
7.113 + @Override
7.114 + public boolean requestShutdown() {
7.115 + agent.closeConnection(shellConnection);
7.116 + return false;
7.117 + }
7.118 +
7.119 + @Override
7.120 + public void connectionInitiated(ShellLaunchEvent ev) {
7.121 + }
7.122 +
7.123 + @Override
7.124 + public void handshakeCompleted(ShellLaunchEvent ev) {
7.125 + }
7.126 +
7.127 + @Override
7.128 + public void connectionClosed(ShellLaunchEvent ev) {
7.129 + synchronized (this) {
7.130 + if (ev.getConnection() != this.shellConnection || closed) {
7.131 + return;
7.132 + }
7.133 + closed = true;
7.134 + }
7.135 +// shellEnv.reportClosedBridge(reportSession, true);
7.136 + }
7.137 +
7.138 + @Override
7.139 + public void agentDestroyed(ShellLaunchEvent ev) {
7.140 + synchronized (this) {
7.141 + if (ev.getAgent() != agent || closed) {
7.142 + return;
7.143 + }
7.144 + closed = true;
7.145 + }
7.146 +// shellEnv.reportClosedBridge(reportSession, false);
7.147 + }
7.148 +
7.149 +}
8.1 --- a/jshell.support/src/org/netbeans/modules/jshell/launch/JShellConnection.java Wed Apr 06 13:12:27 2016 +0200
8.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/launch/JShellConnection.java Thu Apr 07 14:00:03 2016 +0200
8.3 @@ -81,7 +81,7 @@
8.4 * The connection is only valid during its operational time.
8.5 * @author sdedic
8.6 */
8.7 -public final class JShellConnection {
8.8 +public final class JShellConnection implements AutoCloseable {
8.9 private static final Logger LOG = Logger.getLogger(JShellConnection.class.getName());
8.10
8.11 private static final int WRITE_TIMEOUT = 10000;
8.12 @@ -163,6 +163,14 @@
8.13 return agentHandle;
8.14 }
8.15
8.16 + public int getRemoteAgentId() {
8.17 + try {
8.18 + return ((InetSocketAddress)controlSocket.getRemoteAddress()).getPort();
8.19 + } catch (IOException ex) {
8.20 + return -1;
8.21 + }
8.22 + }
8.23 +
8.24 /**
8.25 * Simple wrapper, which interprets close() call as local close and will
8.26 * fire appropriate disconnect events
8.27 @@ -205,6 +213,10 @@
8.28 return theAgent;
8.29 }
8.30
8.31 + public void close() {
8.32 + shutDown();
8.33 + }
8.34 +
8.35 /**
8.36 * Shuts down the connection, may be called for local or remote close.
8.37 */
9.1 --- a/jshell.support/src/org/netbeans/modules/jshell/launch/JShellStartupExtender.java Wed Apr 06 13:12:27 2016 +0200
9.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
9.3 @@ -1,106 +0,0 @@
9.4 -/*
9.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
9.6 - *
9.7 - * Copyright 2016 Oracle and/or its affiliates. All rights reserved.
9.8 - *
9.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
9.10 - * Other names may be trademarks of their respective owners.
9.11 - *
9.12 - * The contents of this file are subject to the terms of either the GNU
9.13 - * General Public License Version 2 only ("GPL") or the Common
9.14 - * Development and Distribution License("CDDL") (collectively, the
9.15 - * "License"). You may not use this file except in compliance with the
9.16 - * License. You can obtain a copy of the License at
9.17 - * http://www.netbeans.org/cddl-gplv2.html
9.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
9.19 - * specific language governing permissions and limitations under the
9.20 - * License. When distributing the software, include this License Header
9.21 - * Notice in each file and include the License file at
9.22 - * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
9.23 - * particular file as subject to the "Classpath" exception as provided
9.24 - * by Oracle in the GPL Version 2 section of the License file that
9.25 - * accompanied this code. If applicable, add the following below the
9.26 - * License Header, with the fields enclosed by brackets [] replaced by
9.27 - * your own identifying information:
9.28 - * "Portions Copyrighted [year] [name of copyright owner]"
9.29 - *
9.30 - * If you wish your version of this file to be governed by only the CDDL
9.31 - * or only the GPL Version 2, indicate your decision by adding
9.32 - * "[Contributor] elects to include this software in this distribution
9.33 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
9.34 - * single choice of license, a recipient has the option to distribute
9.35 - * your version of this file under either the CDDL, the GPL Version 2 or
9.36 - * to extend the choice of license to its licensees as provided above.
9.37 - * However, if you add GPL Version 2 code and therefore, elected the GPL
9.38 - * Version 2 license, then the option applies only if the new code is
9.39 - * made subject to such option by the copyright holder.
9.40 - *
9.41 - * Contributor(s):
9.42 - *
9.43 - * Portions Copyrighted 2016 Sun Microsystems, Inc.
9.44 - */
9.45 -package org.netbeans.modules.jshell.launch;
9.46 -
9.47 -import java.io.File;
9.48 -import java.io.IOException;
9.49 -import java.net.InetSocketAddress;
9.50 -import java.util.ArrayList;
9.51 -import java.util.Collections;
9.52 -import java.util.List;
9.53 -import java.util.logging.Level;
9.54 -import java.util.logging.Logger;
9.55 -import org.netbeans.api.extexecution.startup.StartupExtender.StartMode;
9.56 -import org.netbeans.api.project.Project;
9.57 -import org.netbeans.modules.java.j2seproject.api.J2SEPropertyEvaluator;
9.58 -import org.netbeans.modules.jshell.project.LaunchedProjectOpener;
9.59 -import org.netbeans.modules.jshell.project.ProjectUtils;
9.60 -import org.netbeans.spi.extexecution.startup.StartupExtenderImplementation;
9.61 -import org.openide.modules.InstalledFileLocator;
9.62 -import org.openide.util.Lookup;
9.63 -
9.64 -/**
9.65 - * Hooks onto the J2SE project startup, and injects JShell agent as java agent.
9.66 - *
9.67 - * @author sdedic
9.68 - */
9.69 -@StartupExtenderImplementation.Registration(displayName = "Java Shell", startMode = StartMode.DEBUG)
9.70 -public class JShellStartupExtender implements StartupExtenderImplementation {
9.71 - private static final Logger LOG = Logger.getLogger(JShellStartupExtender.class.getName());
9.72 -
9.73 - @Override
9.74 - public List<String> getArguments(Lookup context, StartMode mode) {
9.75 - LaunchedProjectOpener.init();
9.76 -
9.77 - if (mode != StartMode.DEBUG &&
9.78 - mode != StartMode.TEST_DEBUG) {
9.79 - return Collections.emptyList();
9.80 - }
9.81 - Project p = context.lookup(Project.class);
9.82 - if (p == null) {
9.83 - return Collections.emptyList();
9.84 - }
9.85 -
9.86 - LOG.log(Level.FINE, "Augmenting {0} of project {1}", new Object[] { mode, p });
9.87 -
9.88 - InetSocketAddress isa;
9.89 - ShellAgent agent;
9.90 - // first check that the project has JShell enabled:
9.91 - if (!ProjectUtils.isJShellRunEnabled(p)) {
9.92 - LOG.log(Level.FINE, "Request for agent: Project {0} does not enable Java Shell.", p);
9.93 - return Collections.emptyList();
9.94 - }
9.95 - try {
9.96 - agent = ShellLaunchManager.getInstance().openForProject(p, true);
9.97 - isa = agent.getHandshakeAddress();
9.98 - } catch (IOException ex) {
9.99 - LOG.log(Level.INFO, "Could not obtain handshake address and key: ", ex);
9.100 - return Collections.emptyList();
9.101 - }
9.102 - LOG.log(Level.FINE, "Connect address is: {0}:{1}", new Object[] { isa.getHostString(), isa.getPort() });
9.103 -
9.104 - J2SEPropertyEvaluator prjEval = p.getLookup().lookup(J2SEPropertyEvaluator.class);
9.105 - List<String> args = ShellLaunchManager.buildLocalJVMAgentArgs(agent, prjEval.evaluator()::getProperty);
9.106 - LOG.log(Level.FINE, "Final args: {0}", args);
9.107 - return args;
9.108 - }
9.109 -}
10.1 --- a/jshell.support/src/org/netbeans/modules/jshell/launch/NIOStreams.java Wed Apr 06 13:12:27 2016 +0200
10.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/launch/NIOStreams.java Thu Apr 07 14:00:03 2016 +0200
10.3 @@ -310,7 +310,7 @@
10.4 byte out = (byte)(b & 0xff);
10.5 singleBuffer.clear();
10.6 singleBuffer.put(out);
10.7 -
10.8 + singleBuffer.flip();
10.9 int sel;
10.10
10.11 do {
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/launch/RemoteJShellAccessor.java Thu Apr 07 14:00:03 2016 +0200
11.3 @@ -0,0 +1,49 @@
11.4 +/*
11.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
11.6 + *
11.7 + * Copyright 2016 Oracle and/or its affiliates. All rights reserved.
11.8 + *
11.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
11.10 + * Other names may be trademarks of their respective owners.
11.11 + *
11.12 + * The contents of this file are subject to the terms of either the GNU
11.13 + * General Public License Version 2 only ("GPL") or the Common
11.14 + * Development and Distribution License("CDDL") (collectively, the
11.15 + * "License"). You may not use this file except in compliance with the
11.16 + * License. You can obtain a copy of the License at
11.17 + * http://www.netbeans.org/cddl-gplv2.html
11.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
11.19 + * specific language governing permissions and limitations under the
11.20 + * License. When distributing the software, include this License Header
11.21 + * Notice in each file and include the License file at
11.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
11.23 + * particular file as subject to the "Classpath" exception as provided
11.24 + * by Oracle in the GPL Version 2 section of the License file that
11.25 + * accompanied this code. If applicable, add the following below the
11.26 + * License Header, with the fields enclosed by brackets [] replaced by
11.27 + * your own identifying information:
11.28 + * "Portions Copyrighted [year] [name of copyright owner]"
11.29 + *
11.30 + * If you wish your version of this file to be governed by only the CDDL
11.31 + * or only the GPL Version 2, indicate your decision by adding
11.32 + * "[Contributor] elects to include this software in this distribution
11.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
11.34 + * single choice of license, a recipient has the option to distribute
11.35 + * your version of this file under either the CDDL, the GPL Version 2 or
11.36 + * to extend the choice of license to its licensees as provided above.
11.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
11.38 + * Version 2 license, then the option applies only if the new code is
11.39 + * made subject to such option by the copyright holder.
11.40 + *
11.41 + * Contributor(s):
11.42 + *
11.43 + * Portions Copyrighted 2016 Sun Microsystems, Inc.
11.44 + */
11.45 +package org.netbeans.modules.jshell.launch;
11.46 +
11.47 +import jdk.jshell.RemoteJShellService;
11.48 +import org.netbeans.modules.jshell.launch.JShellConnection;
11.49 +
11.50 +public interface RemoteJShellAccessor extends RemoteJShellService {
11.51 + public JShellConnection getOpenedConnection();
11.52 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/launch/RunExecutionEnvironment.java Thu Apr 07 14:00:03 2016 +0200
12.3 @@ -0,0 +1,264 @@
12.4 +/*
12.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
12.6 + *
12.7 + * Copyright 2016 Oracle and/or its affiliates. All rights reserved.
12.8 + *
12.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
12.10 + * Other names may be trademarks of their respective owners.
12.11 + *
12.12 + * The contents of this file are subject to the terms of either the GNU
12.13 + * General Public License Version 2 only ("GPL") or the Common
12.14 + * Development and Distribution License("CDDL") (collectively, the
12.15 + * "License"). You may not use this file except in compliance with the
12.16 + * License. You can obtain a copy of the License at
12.17 + * http://www.netbeans.org/cddl-gplv2.html
12.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
12.19 + * specific language governing permissions and limitations under the
12.20 + * License. When distributing the software, include this License Header
12.21 + * Notice in each file and include the License file at
12.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
12.23 + * particular file as subject to the "Classpath" exception as provided
12.24 + * by Oracle in the GPL Version 2 section of the License file that
12.25 + * accompanied this code. If applicable, add the following below the
12.26 + * License Header, with the fields enclosed by brackets [] replaced by
12.27 + * your own identifying information:
12.28 + * "Portions Copyrighted [year] [name of copyright owner]"
12.29 + *
12.30 + * If you wish your version of this file to be governed by only the CDDL
12.31 + * or only the GPL Version 2, indicate your decision by adding
12.32 + * "[Contributor] elects to include this software in this distribution
12.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
12.34 + * single choice of license, a recipient has the option to distribute
12.35 + * your version of this file under either the CDDL, the GPL Version 2 or
12.36 + * to extend the choice of license to its licensees as provided above.
12.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
12.38 + * Version 2 license, then the option applies only if the new code is
12.39 + * made subject to such option by the copyright holder.
12.40 + *
12.41 + * Contributor(s):
12.42 + *
12.43 + * Portions Copyrighted 2016 Sun Microsystems, Inc.
12.44 + */
12.45 +package org.netbeans.modules.jshell.launch;
12.46 +
12.47 +import java.io.IOException;
12.48 +import java.io.InputStream;
12.49 +import java.io.ObjectInputStream;
12.50 +import java.io.ObjectOutputStream;
12.51 +import java.io.OutputStream;
12.52 +import java.util.Map;
12.53 +import java.util.Map.Entry;
12.54 +import java.util.concurrent.Executor;
12.55 +import jdk.internal.jshell.remote.RemoteCodes;
12.56 +import jdk.jshell.NbExecutionControl;
12.57 +import org.openide.awt.StatusDisplayer;
12.58 +
12.59 +/**
12.60 + * Exec environment suitable for machines without active JDI connection.
12.61 + *
12.62 + * @author sdedic
12.63 + */
12.64 +public class RunExecutionEnvironment implements RemoteJShellAccessor, Executor, ShellLaunchListener {
12.65 + private final ShellAgent agent;
12.66 +
12.67 + private boolean added;
12.68 + private volatile boolean closed;
12.69 + private JShellConnection shellConnection;
12.70 + private ObjectInputStream dis;
12.71 + private ObjectOutputStream dos;
12.72 +
12.73 + public RunExecutionEnvironment(ShellAgent agent) {
12.74 + this.agent = agent;
12.75 + }
12.76 +
12.77 + public JShellConnection getOpenedConnection() {
12.78 + synchronized (this) {
12.79 + return shellConnection;
12.80 + }
12.81 + }
12.82 +
12.83 + @Override
12.84 + public void redefineClasses(Map<Object, byte[]> redefines) throws IOException, IllegalStateException {
12.85 + if (dis == null || dos == null) {
12.86 + throw new UnsupportedOperationException("streams not opened");
12.87 + }
12.88 + dos.writeInt(NbExecutionControl.CMD_REDEFINE);
12.89 + dos.writeInt(redefines.size());
12.90 + for (Entry<Object, byte[]> en : redefines.entrySet()) {
12.91 + Long l = (Long)en.getKey();
12.92 +
12.93 + dos.writeLong(l);
12.94 + dos.writeObject(en.getValue());
12.95 + }
12.96 + dos.flush();
12.97 +
12.98 + int code = dis.readInt();
12.99 + if (code == RemoteCodes.RESULT_SUCCESS) {
12.100 + return;
12.101 + }
12.102 + if (code == RemoteCodes.RESULT_FAIL) {
12.103 + String msg = dis.readUTF();
12.104 + throw new IllegalStateException(msg);
12.105 + } else {
12.106 + throw new IOException("Invalid response code");
12.107 + }
12.108 + }
12.109 +
12.110 + @Override
12.111 + public Object getClassHandle(String className) {
12.112 + if (dis == null || dos == null) {
12.113 + // no class sent over -> no class ever could be defined.
12.114 + return null;
12.115 + }
12.116 + try {
12.117 + dos.writeInt(NbExecutionControl.CMD_CLASSID);
12.118 + dos.writeUTF(className);
12.119 + dos.flush();
12.120 +
12.121 + int code = dis.readInt();
12.122 + if (code != RemoteCodes.RESULT_SUCCESS) {
12.123 + return null;
12.124 + }
12.125 + long l = dis.readLong();
12.126 + return l == -1 ? null : l;
12.127 + } catch (IOException ex) {
12.128 + return null;
12.129 + }
12.130 + }
12.131 +
12.132 + @Override
12.133 + public Executor getCodeExecutor() {
12.134 + return this;
12.135 + }
12.136 +
12.137 + @Override
12.138 + public void waitConnected(long millis) throws IOException {
12.139 + getConnection(false);
12.140 + }
12.141 +
12.142 + /**
12.143 + * Sends stop user code instruction. Must create a separate connection to the agent
12.144 + * @return
12.145 + * @throws IllegalStateException
12.146 + */
12.147 + @Override
12.148 + public boolean sendStopUserCode() throws IOException {
12.149 + int id = this.shellConnection.getRemoteAgentId();
12.150 + try (JShellConnection stopConnection = agent.createConnection();
12.151 + ObjectInputStream in = new ObjectInputStream(stopConnection.getAgentOutput());
12.152 + ObjectOutputStream out = new ObjectOutputStream(stopConnection.getAgentInput())
12.153 + ) {
12.154 +
12.155 + out.writeInt(NbExecutionControl.CMD_STOP);
12.156 + out.writeInt(id);
12.157 + out.flush();
12.158 +
12.159 + int success = in.readInt();
12.160 + return success == RemoteCodes.RESULT_SUCCESS;
12.161 + }
12.162 + }
12.163 +
12.164 + @Override
12.165 + public String decorateLaunchArgs(String baseArgs) {
12.166 + return baseArgs;
12.167 + }
12.168 +
12.169 + @Override
12.170 + public boolean requestShutdown() {
12.171 + agent.closeConnection(shellConnection);
12.172 + return false;
12.173 + }
12.174 +
12.175 + private JShellConnection getConnection(boolean dontConnect) throws IOException {
12.176 + synchronized (this) {
12.177 + if (closed || (dontConnect && shellConnection == null)) {
12.178 + throw new IOException(Bundle.MSG_AgentConnectionBroken());
12.179 + }
12.180 + if (shellConnection != null) {
12.181 + return shellConnection;
12.182 + }
12.183 + }
12.184 + try {
12.185 + JShellConnection x = agent.createConnection();
12.186 + synchronized (this) {
12.187 + if (!added) {
12.188 + ShellLaunchManager.getInstance().addLaunchListener(this);
12.189 + added = true;
12.190 + }
12.191 + return this.shellConnection = x;
12.192 + }
12.193 + } catch (IOException ex) {
12.194 + StatusDisplayer.getDefault().setStatusText(Bundle.MSG_ErrorConnectingToAgent(ex.getLocalizedMessage()), 100);
12.195 + throw ex;
12.196 + }
12.197 + }
12.198 +
12.199 + @Override
12.200 + public OutputStream getCommandStream() throws IOException {
12.201 + if (dos != null) {
12.202 + return dos;
12.203 + }
12.204 + return dos = new ObjectOutputStream(getConnection(true).getAgentInput());
12.205 + }
12.206 +
12.207 + @Override
12.208 + public InputStream getResponseStream() throws IOException {
12.209 + if (dis != null) {
12.210 +
12.211 + }
12.212 + return dis = new ObjectInputStream(getConnection(true).getAgentOutput());
12.213 + }
12.214 +
12.215 + @Override
12.216 + public synchronized void closeStreams() {
12.217 + if (shellConnection == null) {
12.218 + return;
12.219 + }
12.220 + try {
12.221 + OutputStream os = shellConnection.getAgentInput();
12.222 + os.close();
12.223 + } catch (IOException ex) {
12.224 + }
12.225 + try {
12.226 + InputStream is = shellConnection.getAgentOutput();
12.227 + is.close();
12.228 + } catch (IOException ex) {
12.229 + }
12.230 +
12.231 + requestShutdown();
12.232 + }
12.233 +
12.234 + @Override
12.235 + public void connectionInitiated(ShellLaunchEvent ev) { }
12.236 +
12.237 + @Override
12.238 + public void handshakeCompleted(ShellLaunchEvent ev) { }
12.239 +
12.240 + @Override
12.241 + public void connectionClosed(ShellLaunchEvent ev) {
12.242 + synchronized (this) {
12.243 + if (ev.getConnection() != this.shellConnection || closed) {
12.244 + return;
12.245 + }
12.246 + closed = true;
12.247 + }
12.248 + ShellLaunchManager.getInstance().removeLaunchListener(this);
12.249 + }
12.250 +
12.251 + @Override
12.252 + public void agentDestroyed(ShellLaunchEvent ev) {
12.253 + synchronized (this) {
12.254 + if (ev.getAgent() != agent || closed) {
12.255 + return;
12.256 + }
12.257 + this.shellConnection = null;
12.258 + closed = true;
12.259 + }
12.260 + ShellLaunchManager.getInstance().removeLaunchListener(this);
12.261 + }
12.262 +
12.263 + @Override
12.264 + public void execute(Runnable command) {
12.265 + command.run();
12.266 + }
12.267 +}
13.1 --- a/jshell.support/src/org/netbeans/modules/jshell/launch/ShellAgent.java Wed Apr 06 13:12:27 2016 +0200
13.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/launch/ShellAgent.java Thu Apr 07 14:00:03 2016 +0200
13.3 @@ -294,4 +294,18 @@
13.4 }
13.5 return con;
13.6 }
13.7 +
13.8 + public RemoteJShellAccessor createRemoteService() throws IOException {
13.9 + if (closed) {
13.10 + throw new IOException("Closed");
13.11 + }
13.12 + if (expectDebugger) {
13.13 + if (debuggerSession == null) {
13.14 + throw new IOException("Debugger unavailable");
13.15 + }
13.16 + return new DebugExecutionEnvironment(this);
13.17 + } else {
13.18 + return new RunExecutionEnvironment(this);
13.19 + }
13.20 + }
13.21 }
14.1 --- a/jshell.support/src/org/netbeans/modules/jshell/launch/ShellDebuggerUtils.java Wed Apr 06 13:12:27 2016 +0200
14.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/launch/ShellDebuggerUtils.java Thu Apr 07 14:00:03 2016 +0200
14.3 @@ -79,6 +79,9 @@
14.4 }
14.5
14.6 static ObjectReference getWorkerHandle(Session debuggerSession, int remotePortAddress) {
14.7 + if (debuggerSession == null) {
14.8 + return null;
14.9 + }
14.10 JPDADebugger debugger = debuggerSession.lookupFirst(null, JPDADebugger.class);
14.11 if (debugger == null) {
14.12 return null;
15.1 --- a/jshell.support/src/org/netbeans/modules/jshell/project/LaunchedProjectOpener.java Wed Apr 06 13:12:27 2016 +0200
15.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/project/LaunchedProjectOpener.java Thu Apr 07 14:00:03 2016 +0200
15.3 @@ -102,7 +102,7 @@
15.4 return;
15.5 }
15.6
15.7 - final JShellEnvironment attachEnv = new DebugShellEnv(agent, p,
15.8 + final JShellEnvironment attachEnv = new ProjectShellEnv(agent, p,
15.9 Bundle.Title_JShellOnDebugger(ProjectUtils.getInformation(p).getDisplayName()));
15.10
15.11 boolean ok = false;
15.12 @@ -119,31 +119,6 @@
15.13 }
15.14 }
15.15
15.16 - private static class DebugShellEnv extends JShellEnvironment {
15.17 - private final ShellAgent agent;
15.18 -
15.19 - public DebugShellEnv(ShellAgent agent, Project project, String displayName) {
15.20 - super(project, displayName);
15.21 - this.agent = agent;
15.22 - }
15.23 -
15.24 - @Override
15.25 - protected InputOutput createInputOutput() {
15.26 - return agent.getIO();
15.27 - }
15.28 -
15.29 - public RemoteJShellService createExecutionEnv() {
15.30 - return new DebugExecutionEnvironment(getSession(), agent, this);
15.31 - }
15.32 -
15.33 - protected void reportClosedBridge(ShellSession s, boolean disconnectOrShutdown) {
15.34 - if (disconnectOrShutdown) {
15.35 - notifyDisconnected(s);
15.36 - } else {
15.37 - notifyShutdown();
15.38 - }
15.39 - }
15.40 - }
15.41
15.42 @Override
15.43 public void agentDestroyed(ShellLaunchEvent ev) { }
15.44 @@ -151,125 +126,4 @@
15.45 @Override
15.46 public void connectionClosed(ShellLaunchEvent ev) { }
15.47
15.48 - static class DebugExecutionEnvironment extends JDIRemoteAgent implements ShellLaunchListener {
15.49 - private boolean added;
15.50 - volatile JShellConnection shellConnection;
15.51 - private boolean closed;
15.52 -
15.53 - final ShellAgent agent;
15.54 - final DebugShellEnv shellEnv;
15.55 - final ShellSession reportSession;
15.56 -
15.57 - public DebugExecutionEnvironment(ShellSession s, ShellAgent agent, DebugShellEnv env) {
15.58 - super(UnaryOperator.identity());
15.59 - this.shellEnv = env;
15.60 - this.agent = agent;
15.61 - this.reportSession = s;
15.62 - }
15.63 -
15.64 - @NbBundle.Messages({
15.65 - "MSG_AgentConnectionBroken=Connection to Java Shell agent broken. Please re-run the project.",
15.66 - "# {0} - error message",
15.67 - "MSG_ErrorConnectingToAgent=Error connecting to Java Shell agent: {0}"
15.68 - })
15.69 - private JShellConnection getConnection(boolean dontConnect) throws IOException {
15.70 - synchronized (this) {
15.71 - if (closed || (dontConnect && shellConnection == null)) {
15.72 - throw new IOException(Bundle.MSG_AgentConnectionBroken());
15.73 - }
15.74 - if (shellConnection != null) {
15.75 - return shellConnection;
15.76 - }
15.77 - }
15.78 - try {
15.79 - JShellConnection x = agent.createConnection();
15.80 - synchronized (this) {
15.81 - if (!added) {
15.82 - ShellLaunchManager.getInstance().addLaunchListener(this);
15.83 - added = true;
15.84 - }
15.85 - return this.shellConnection = x;
15.86 - }
15.87 - } catch (IOException ex) {
15.88 - StatusDisplayer.getDefault().setStatusText(Bundle.MSG_ErrorConnectingToAgent(ex.getLocalizedMessage()), 100);
15.89 - throw ex;
15.90 - }
15.91 - }
15.92 -
15.93 - @Override
15.94 - public OutputStream getCommandStream() throws IOException {
15.95 - return getConnection(true).getAgentInput();
15.96 - }
15.97 -
15.98 - @Override
15.99 - public InputStream getResponseStream() throws IOException {
15.100 - return getConnection(true).getAgentOutput();
15.101 - }
15.102 -
15.103 - @Override
15.104 - public synchronized void closeStreams() {
15.105 - if (shellConnection == null) {
15.106 - return;
15.107 - }
15.108 - try {
15.109 - OutputStream os = shellConnection.getAgentInput();
15.110 - os.close();
15.111 - } catch (IOException ex) {
15.112 - }
15.113 - try {
15.114 - InputStream is = shellConnection.getAgentOutput();
15.115 - is.close();
15.116 - } catch (IOException ex) {
15.117 - }
15.118 -
15.119 - requestShutdown();
15.120 - }
15.121 -
15.122 - @Override
15.123 - protected ObjectReference getAgentObjectReference() {
15.124 - return shellConnection.getAgentHandle();
15.125 - }
15.126 -
15.127 - @Override
15.128 - protected VirtualMachine acquireVirtualMachine() throws IOException {
15.129 - return getConnection(false).getVirtualMachine();
15.130 - }
15.131 -
15.132 - @Override
15.133 - public boolean requestShutdown() {
15.134 - agent.closeConnection(shellConnection);
15.135 - return false;
15.136 - }
15.137 -
15.138 - @Override
15.139 - public void connectionInitiated(ShellLaunchEvent ev) {
15.140 - }
15.141 -
15.142 - @Override
15.143 - public void handshakeCompleted(ShellLaunchEvent ev) {
15.144 - }
15.145 -
15.146 - @Override
15.147 - public void connectionClosed(ShellLaunchEvent ev) {
15.148 - synchronized (this) {
15.149 - if (closed) {
15.150 - return;
15.151 - }
15.152 - closed = true;
15.153 - }
15.154 - shellEnv.reportClosedBridge(reportSession, true);
15.155 - }
15.156 -
15.157 - @Override
15.158 - public void agentDestroyed(ShellLaunchEvent ev) {
15.159 - synchronized (this) {
15.160 - if (ev.getAgent() != agent || closed) {
15.161 - return;
15.162 - }
15.163 - this.shellConnection = null;
15.164 - closed = true;
15.165 - }
15.166 - shellEnv.reportClosedBridge(reportSession, false);
15.167 - }
15.168 - }
15.169 }
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/project/ProjectShellEnv.java Thu Apr 07 14:00:03 2016 +0200
16.3 @@ -0,0 +1,100 @@
16.4 +/*
16.5 + * To change this license header, choose License Headers in Project Properties.
16.6 + * To change this template file, choose Tools | Templates
16.7 + * and open the template in the editor.
16.8 + */
16.9 +package org.netbeans.modules.jshell.project;
16.10 +
16.11 +import org.netbeans.modules.jshell.launch.RemoteJShellAccessor;
16.12 +import java.io.IOException;
16.13 +import jdk.jshell.RemoteJShellService;
16.14 +import org.netbeans.api.project.Project;
16.15 +import org.netbeans.modules.jshell.env.JShellEnvironment;
16.16 +import org.netbeans.modules.jshell.launch.JShellConnection;
16.17 +import org.netbeans.modules.jshell.launch.ShellAgent;
16.18 +import org.netbeans.modules.jshell.launch.ShellLaunchEvent;
16.19 +import org.netbeans.modules.jshell.launch.ShellLaunchListener;
16.20 +import org.netbeans.modules.jshell.launch.ShellLaunchManager;
16.21 +import org.netbeans.modules.jshell.support.ShellSession;
16.22 +import org.openide.windows.InputOutput;
16.23 +
16.24 +/**
16.25 + *
16.26 + * @author sdedic
16.27 + */
16.28 +class ProjectShellEnv extends JShellEnvironment {
16.29 + private final ShellAgent agent;
16.30 +
16.31 + public ProjectShellEnv(ShellAgent agent, Project project, String displayName) {
16.32 + super(project, displayName);
16.33 + this.agent = agent;
16.34 + }
16.35 +
16.36 + @Override
16.37 + protected InputOutput createInputOutput() {
16.38 + return agent.getIO();
16.39 + }
16.40 +
16.41 + public RemoteJShellService createExecutionEnv() {
16.42 + try {
16.43 + RemoteJShellAccessor accessor = agent.createRemoteService();
16.44 + CloseNotifier nf = new CloseNotifier(accessor, getSession());
16.45 + ShellLaunchManager.getInstance().addLaunchListener(nf);
16.46 + return accessor;
16.47 + } catch (IOException ex) {
16.48 + return null;
16.49 + }
16.50 + }
16.51 +
16.52 + protected void reportClosedBridge(ShellSession s, boolean disconnectOrShutdown) {
16.53 + if (disconnectOrShutdown) {
16.54 + notifyDisconnected(s);
16.55 + } else {
16.56 + notifyShutdown();
16.57 + }
16.58 + }
16.59 +
16.60 + private class CloseNotifier implements ShellLaunchListener {
16.61 + private final RemoteJShellAccessor accessor;
16.62 + private final ShellSession session;
16.63 + private boolean closed;
16.64 +
16.65 + public CloseNotifier(RemoteJShellAccessor accessor, ShellSession session) {
16.66 + this.accessor = accessor;
16.67 + this.session = session;
16.68 + }
16.69 +
16.70 + @Override
16.71 + public void connectionClosed(ShellLaunchEvent ev) {
16.72 + JShellConnection c = ev.getConnection();
16.73 + synchronized (this) {
16.74 + if (closed || c != accessor.getOpenedConnection()) {
16.75 + return;
16.76 + }
16.77 + closed = true;
16.78 + }
16.79 +
16.80 + notifyDisconnected(session);
16.81 + ShellLaunchManager.getInstance().removeLaunchListener(this);
16.82 + }
16.83 +
16.84 + @Override
16.85 + public void agentDestroyed(ShellLaunchEvent ev) {
16.86 + synchronized (this) {
16.87 + if (closed || ev.getAgent() != agent) {
16.88 + return;
16.89 + }
16.90 + closed = true;
16.91 + }
16.92 + notifyShutdown();
16.93 + ShellLaunchManager.getInstance().removeLaunchListener(this);
16.94 + }
16.95 +
16.96 + @Override
16.97 + public void connectionInitiated(ShellLaunchEvent ev) {}
16.98 +
16.99 + @Override
16.100 + public void handshakeCompleted(ShellLaunchEvent ev) {}
16.101 +
16.102 + }
16.103 +}
17.1 --- a/jshell.support/src/org/netbeans/modules/jshell/support/ShellSession.java Wed Apr 06 13:12:27 2016 +0200
17.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/support/ShellSession.java Thu Apr 07 14:00:03 2016 +0200
17.3 @@ -694,7 +694,7 @@
17.4 this.shell = shell;
17.5 // it's possible that the shell's startup will terminate the session
17.6 if (isValid()) {
17.7 - shell.onShutdown(sh -> closed());
17.8 + shell.onShutdown(sh -> closedDelayed());
17.9 model.attach(shell);
17.10 // must first give chance to the model to map the snippet to console contents
17.11 model.forwardSnippetEvent(this::acceptSnippet);
17.12 @@ -890,9 +890,22 @@
17.13 }
17.14
17.15 private void closed() {
17.16 - this.closed = true;
17.17 + synchronized (this) {
17.18 + if (closed) {
17.19 + return;
17.20 + }
17.21 + this.closed = true;
17.22 + }
17.23 propSupport.firePropertyChange(PROP_ACTIVE, true, false);
17.24 }
17.25 +
17.26 + private void closedDelayed() {
17.27 + FORCE_CLOSE_RP.post(new Runnable() {
17.28 + public void run() {
17.29 + closed();
17.30 + }
17.31 + }, 300);
17.32 + }
17.33
17.34 private synchronized void init(ShellSession prev) {
17.35 evaluator = new RequestProcessor("Evaluator for " + displayName);
18.1 --- a/lib.jshell.agent/agentsrc/jdk/internal/jshell/remote/AgentWorker.java Wed Apr 06 13:12:27 2016 +0200
18.2 +++ b/lib.jshell.agent/agentsrc/jdk/internal/jshell/remote/AgentWorker.java Thu Apr 07 14:00:03 2016 +0200
18.3 @@ -62,6 +62,7 @@
18.4 import java.util.logging.Level;
18.5 import java.util.logging.Logger;
18.6 import java.util.regex.Pattern;
18.7 +import static jdk.internal.jshell.remote.RemoteCodes.RESULT_KILLED;
18.8 import org.netbeans.lib.jshell.agent.NbJShellAgent;
18.9
18.10 /**
18.11 @@ -69,7 +70,9 @@
18.12 * @author sdedic
18.13 */
18.14 public class AgentWorker extends RemoteAgent implements Executor, Runnable {
18.15 - public static final String PROPERTY_EXECUTOR = "jdk.internal.jshell.remote.AgentWorker.executor"; // NOI18N
18.16 + private static final Logger LOG = Logger.getLogger("org.netbeans.lib.jshell.agent.AgentWorker"); // NOI18N
18.17 +
18.18 + public static final String PROPERTY_EXECUTOR = "org.netbeans.lib.jshell.agent.AgentWorker.executor"; // NOI18N
18.19
18.20 /**
18.21 * Reference set by instrumented classes
18.22 @@ -91,18 +94,46 @@
18.23 * The Classloader last obtained from a field or method
18.24 */
18.25 private ClassLoader lastClassLoader;
18.26 +
18.27 + /**
18.28 + * Provider for the classloader. Contacted before every user invocation
18.29 + * and before every class load.
18.30 + */
18.31 private Callable<ClassLoader> loaderProvider;
18.32 +
18.33 +
18.34 + /**
18.35 + * Executor for user's code. Can be provided from the environment using System.properties,
18.36 + * see {@link #PROPERTY_EXECUTOR}.
18.37 + */
18.38 private Executor userExecutor;
18.39 - // perform classloader transformation
18.40 - private boolean doClassTransform;
18.41 +
18.42 + /**
18.43 + * Threads which execute user code, keyed by agent's socket local port.
18.44 + */
18.45 + // @GuardedBy(self)
18.46 + private final static Map<Integer, Thread> userCodeExecutingThreads = new HashMap<>();
18.47
18.48 private AgentWorker() {
18.49 agent = null;
18.50 socket = null;
18.51 socketPort = -1;
18.52 -
18.53 - Executor exec = (Executor)System.getProperties().get(PROPERTY_EXECUTOR);
18.54 - this.userExecutor = exec != null ? exec : this;
18.55 + this.userExecutor = findExecutor();
18.56 + }
18.57 +
18.58 + private Executor findExecutor() {
18.59 + Object o = System.getProperties().get(PROPERTY_EXECUTOR);;
18.60 + if (o instanceof Executor) {
18.61 + this.userExecutor = (Executor)o;
18.62 + } else if (o instanceof String) {
18.63 + try {
18.64 + Class executorClazz = Class.forName((String)o);
18.65 + return (Executor)executorClazz.newInstance();
18.66 + } catch (ReflectiveOperationException ex) {
18.67 + LOG.log(Level.SEVERE, null, ex);
18.68 + }
18.69 + }
18.70 + return this;
18.71 }
18.72
18.73 private static class LoaderAccessor implements Callable<ClassLoader> {
18.74 @@ -203,8 +234,7 @@
18.75 }
18.76 };
18.77 }
18.78 - Executor exec = (Executor)System.getProperties().get(PROPERTY_EXECUTOR);
18.79 - this.userExecutor = exec != null ? exec : this;
18.80 + this.userExecutor = findExecutor();
18.81 }
18.82
18.83 public static void main(String[] args) throws Exception {
18.84 @@ -227,6 +257,8 @@
18.85 // will read immediately
18.86 ObjectInputStream ism = new ObjectInputStream(socket.getInputStream())) {
18.87 commandLoop(ism, osm);
18.88 + } catch (EOFException ex) {
18.89 + // expected.
18.90 } catch (Exception ex) {
18.91 ex.printStackTrace();
18.92 }
18.93 @@ -263,6 +295,7 @@
18.94 }
18.95 result.put(s, props.getProperty(s));
18.96 }
18.97 + LOG.log(Level.FINE, "Sending properties: " + props);
18.98
18.99 prepareClassLoader();
18.100 StringBuilder cp = new StringBuilder();
18.101 @@ -293,7 +326,7 @@
18.102 }
18.103 cp.append(s);
18.104 }
18.105 -
18.106 + LOG.log(Level.FINE, "Classloader path: " + cp);
18.107 result.put("nb.class.path", cp.toString()); // NOI18N
18.108
18.109 o.writeInt(result.size());
18.110 @@ -304,6 +337,52 @@
18.111 o.flush();
18.112 }
18.113
18.114 + private ClassLoader contextLoader;
18.115 +
18.116 + void clientCodeEnter() {
18.117 + LOG.log(Level.FINER, "Entering client code");
18.118 + this.contextLoader = Thread.currentThread().getContextClassLoader();
18.119 + Thread.currentThread().setContextClassLoader(loader);
18.120 + }
18.121 +
18.122 + private boolean killed;
18.123 +
18.124 + /**
18.125 + * Removes our thread from the user-executing map.
18.126 + * It's important that clientCodeLeave is called BEFORE the agent starts to send
18.127 + * response code: either the thread is removed here, and the response code is sent by
18.128 + * the original Agent's code, or the entry is removed by the killer agent before/while
18.129 + * executing agent is waiting to lock the map - and in that case the `killed' will be set
18.130 + * to true and response code is produced in performExecute. Since ThreadDeath is thrown,
18.131 + * the executing agent will not complete the synchronized block normally
18.132 + */
18.133 + void clientCodeLeave() {
18.134 + LOG.log(Level.FINER, "Exiting client code");
18.135 + Thread.currentThread().setContextClassLoader(contextLoader);
18.136 + synchronized (userCodeExecutingThreads) {
18.137 + killed = !userCodeExecutingThreads.remove(socketPort, Thread.currentThread());
18.138 + LOG.log(Level.FINER, "User code killed: {0}", killed);
18.139 + }
18.140 + }
18.141 +
18.142 + private void performExecute(int cmd, ObjectInputStream in, ObjectOutputStream out) throws IOException {
18.143 + killed = false;
18.144 + try {
18.145 + synchronized (userCodeExecutingThreads) {
18.146 + userCodeExecutingThreads.put(socketPort, Thread.currentThread());
18.147 + }
18.148 + super.performCommand(cmd, in, out);
18.149 + return;
18.150 + } catch (ThreadDeath td) {
18.151 + LOG.log(Level.FINE, "Received ThreadDeath, killed: {0}", killed);
18.152 + if (!killed) {
18.153 + throw td;
18.154 + }
18.155 + }
18.156 + out.writeInt(RESULT_KILLED);
18.157 + out.flush();
18.158 + }
18.159 +
18.160 @Override
18.161 protected void performCommand(final int cmd, final ObjectInputStream in, final ObjectOutputStream out) throws IOException {
18.162 try {
18.163 @@ -314,7 +393,7 @@
18.164 userExecutor.execute(new Runnable() {
18.165 public void run() {
18.166 try {
18.167 - AgentWorker.super.performCommand(cmd, in, out);
18.168 + performExecute(cmd, in, out);
18.169 } catch (IOException ex) {
18.170 err[0] = ex;
18.171 }
18.172 @@ -329,12 +408,13 @@
18.173 returnVMInfo(out);
18.174 break;
18.175 case CMD_REDEFINE:
18.176 - performRedefineClass(in, out);
18.177 + performRedefineClasses(in, out);
18.178 break;
18.179 case CMD_CLASSID:
18.180 performClassId(in, out);
18.181 break;
18.182 case CMD_STOP:
18.183 + performStop(in, out);
18.184 break;
18.185 default:
18.186 super.performCommand(cmd, in, out);
18.187 @@ -345,19 +425,54 @@
18.188 }
18.189 }
18.190
18.191 - private void performRedefineClass(ObjectInputStream in, ObjectOutputStream out) throws IOException {
18.192 - long classId = in.readLong();
18.193 + /**
18.194 + * Executes STOP command. Note that STOP comes through <b>different</b> agent than
18.195 + * the one which should stop the user's code; the controlling process opens connection
18.196 + * and instructs the VM to stop running thread.
18.197 + * @param in
18.198 + * @param out
18.199 + * @throws IOException
18.200 + */
18.201 + @SuppressWarnings({"deprecation", "CallToThreadStopSuspendOrResumeManager"})
18.202 + private void performStop(ObjectInputStream in, ObjectOutputStream out) throws IOException {
18.203 + int agentId = in.readInt();
18.204 + Thread targetThread;
18.205 +
18.206 + synchronized (userCodeExecutingThreads) {
18.207 + targetThread = userCodeExecutingThreads.remove(agentId);
18.208 + if (targetThread != null) {
18.209 + // throw ThreadDeath in the target thread
18.210 + targetThread.stop();
18.211 + }
18.212 + }
18.213 + if (targetThread != null) {
18.214 + out.writeInt(RemoteCodes.RESULT_SUCCESS);
18.215 + } else {
18.216 + out.writeInt(RemoteCodes.RESULT_FAIL);
18.217 + }
18.218 + out.flush();
18.219 + }
18.220 +
18.221 + private void performRedefineClasses(ObjectInputStream in, ObjectOutputStream out) throws IOException {
18.222 + int count = in.readInt();
18.223 try {
18.224 - byte[] replaceBytecode = (byte[])in.readObject();
18.225 - Class defined = ((NbRemoteLoader)loader).getClassOfId(classId);
18.226 -
18.227 - agent.getInstrumentation().redefineClasses(
18.228 - new ClassDefinition(defined, replaceBytecode)
18.229 - );
18.230 + for (int i = 0; i < count; i++) {
18.231 + long classId = in.readLong();
18.232 + byte[] replaceBytecode = (byte[]) in.readObject();
18.233 + Class defined = ((NbRemoteLoader) loader).getClassOfId(classId);
18.234 +
18.235 + agent.getInstrumentation().redefineClasses(
18.236 + new ClassDefinition(defined, replaceBytecode)
18.237 + );
18.238 + }
18.239 out.writeInt(RemoteCodes.RESULT_SUCCESS);
18.240 - out.writeLong(classId);
18.241 - } catch (ClassNotFoundException | UnmodifiableClassException ex) {
18.242 - Logger.getLogger(AgentWorker.class.getName()).log(Level.SEVERE, null, ex);
18.243 + } catch (UnsupportedOperationException ex) {
18.244 + LOG.log(Level.FINE, "Class redefinition failed");
18.245 + out.writeInt(RemoteCodes.RESULT_FAIL);
18.246 + out.writeInt(RemoteCodes.RESULT_SUCCESS);
18.247 + } catch (LinkageError | NullPointerException | ClassNotFoundException | UnmodifiableClassException ex) {
18.248 + LOG.log(Level.WARNING, "Could not redefine class: ", ex);
18.249 + out.writeInt(RemoteCodes.RESULT_FAIL);
18.250 out.writeInt(RemoteCodes.RESULT_FAIL);
18.251 out.writeUTF(ex.toString());
18.252 }
19.1 --- a/lib.jshell.agent/agentsrc/jdk/internal/jshell/remote/RemoteAgent.java Wed Apr 06 13:12:27 2016 +0200
19.2 +++ b/lib.jshell.agent/agentsrc/jdk/internal/jshell/remote/RemoteAgent.java Thu Apr 07 14:00:03 2016 +0200
19.3 @@ -108,6 +108,7 @@
19.4 // Invoke executable entry point in loaded code
19.5 String name = in.readUTF();
19.6 Class<?> klass = klasses.get(name);
19.7 + prepareClassLoader();
19.8 if (klass == null) {
19.9 debug("*** Invoke failure: no such class loaded %s\n", name);
19.10 out.writeInt(RESULT_FAIL);
19.11 @@ -124,9 +125,9 @@
19.12 clientCodeEnter();
19.13 res = doitMethod.invoke(null, new Object[0]);
19.14 } catch (InvocationTargetException ex) {
19.15 - if (ex.getCause() instanceof StopExecutionException) {
19.16 + if (ex.getCause() instanceof ThreadDeath) {
19.17 expectingStop = false;
19.18 - throw (StopExecutionException) ex.getCause();
19.19 + throw (ThreadDeath) ex.getCause();
19.20 }
19.21 throw ex;
19.22 } catch (StopExecutionException ex) {
20.1 --- a/lib.nbjshell/src/jdk/jshell/NbExecutionControl.java Wed Apr 06 13:12:27 2016 +0200
20.2 +++ b/lib.nbjshell/src/jdk/jshell/NbExecutionControl.java Thu Apr 07 14:00:03 2016 +0200
20.3 @@ -71,6 +71,10 @@
20.4 private static final Logger LOG = Logger.getLogger(NbExecutionControl.class.getName());
20.5
20.6 public static final int CMD_VERSION_INFO = 100;
20.7 +
20.8 + public static final int CMD_REDEFINE = 101;
20.9 + public static final int CMD_STOP = 102;
20.10 + public static final int CMD_CLASSID = 103;
20.11
20.12 private final RemoteJShellService execEnv;
20.13 private final JDIEnv jdi;
20.14 @@ -132,7 +136,8 @@
20.15 try {
20.16 proc.debug(DBG_GEN, "Attempting to stop the client code...\n");
20.17 execEnv.sendStopUserCode();
20.18 - } catch (IllegalStateException ex) {
20.19 + } catch (IllegalStateException | IOException ex) {
20.20 + ex.printStackTrace();
20.21 proc.debug(DBG_GEN, "Exception on remote stop: %s\n", ex.getCause());
20.22 }
20.23 }
20.24 @@ -143,9 +148,9 @@
20.25 OutputStream os = execEnv.getCommandStream();
20.26 InputStream is = execEnv.getResponseStream();
20.27 out = os instanceof ObjectOutputStream ? (ObjectOutputStream)os :
20.28 - new ObjectOutputStream(execEnv.getCommandStream());
20.29 + new ObjectOutputStream(os);
20.30 in = is instanceof ObjectInputStream ? (ObjectInputStream)is :
20.31 - new ObjectInputStream(execEnv.getResponseStream());
20.32 + new ObjectInputStream(is);
20.33
20.34 /*
20.35 try (ServerSocket listener = new ServerSocket(0)) {
21.1 --- a/lib.nbjshell/src/jdk/jshell/RemoteJShellService.java Wed Apr 06 13:12:27 2016 +0200
21.2 +++ b/lib.nbjshell/src/jdk/jshell/RemoteJShellService.java Thu Apr 07 14:00:03 2016 +0200
21.3 @@ -24,7 +24,7 @@
21.4 *
21.5 * @param redefines handle-to-classfile contents map.
21.6 */
21.7 - public void redefineClasses(Map<Object, byte[]> redefines);
21.8 + public void redefineClasses(Map<Object, byte[]> redefines) throws IOException, IllegalStateException;
21.9
21.10 /**
21.11 * Returns handle that corresponds to a named class. Returns null,
21.12 @@ -71,7 +71,7 @@
21.13 * @return true, if the implementation even attempted to stop
21.14 * the machine.
21.15 */
21.16 - public boolean sendStopUserCode() throws IllegalStateException;
21.17 + public boolean sendStopUserCode() throws IllegalStateException, IOException;
21.18
21.19 /**
21.20 * Decorates launcher arguments. Results undefined, if the environment
22.1 --- a/libs.jshell/nbproject/project.xml Wed Apr 06 13:12:27 2016 +0200
22.2 +++ b/libs.jshell/nbproject/project.xml Thu Apr 07 14:00:03 2016 +0200
22.3 @@ -25,6 +25,7 @@
22.4 </module-dependencies>
22.5 <public-packages>
22.6 <package>jdk.internal.jshell.debug</package>
22.7 + <package>jdk.internal.jshell.remote</package>
22.8 <package>jdk.jshell</package>
22.9 </public-packages>
22.10 <class-path-extension>