diff -r 7578d523265c -r 5f03841799a3 api.debugger.jpda/apichanges.xml --- a/api.debugger.jpda/apichanges.xml Tue Aug 26 19:10:03 2014 +0400 +++ b/api.debugger.jpda/apichanges.xml Mon Sep 08 23:07:57 2014 +0200 @@ -875,6 +875,25 @@ + + + + Add information about native methods into EditorContext.Operation. + + + + + + A new method createMethodOperation(), which takes + boolean isNative is added to EditorContext + class. The EditorContext.Operation has isNative() + method to retrieve that information. The implementation retrieves the + native flag from parser information, therefore there can occur native + methods at runtime, which are not marked as native by this flag. + + + + diff -r 7578d523265c -r 5f03841799a3 api.debugger.jpda/manifest.mf --- a/api.debugger.jpda/manifest.mf Tue Aug 26 19:10:03 2014 +0400 +++ b/api.debugger.jpda/manifest.mf Mon Sep 08 23:07:57 2014 +0200 @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.api.debugger.jpda/2 OpenIDE-Module-Localizing-Bundle: org/netbeans/api/debugger/jpda/Bundle.properties -OpenIDE-Module-Specification-Version: 2.50 +OpenIDE-Module-Specification-Version: 2.51 OpenIDE-Module-Package-Dependencies: com.sun.jdi[VirtualMachineManager] diff -r 7578d523265c -r 5f03841799a3 api.debugger.jpda/src/org/netbeans/spi/debugger/jpda/EditorContext.java --- a/api.debugger.jpda/src/org/netbeans/spi/debugger/jpda/EditorContext.java Tue Aug 26 19:10:03 2014 +0400 +++ b/api.debugger.jpda/src/org/netbeans/spi/debugger/jpda/EditorContext.java Mon Sep 08 23:07:57 2014 +0200 @@ -373,7 +373,34 @@ int bytecodeIndex) { return new Operation(startPosition, endPosition, methodStartPosition, methodEndPosition, - methodName, methodClassType, bytecodeIndex); + methodName, methodClassType, bytecodeIndex, false); + } + + /** + * Creates a method operation. + * @param startPosition The starting position of the operation + * @param endPosition The ending position of the operation + * @param methodStartPosition The starting position of the method name + * @param methodEndPosition The ending position of the method name + * @param methodName The string representation of the method name + * @param methodClassType The class type, which defines this method + * @param bytecodeIndex The bytecode index of this method call + * @param isNative true when the method is determined as a native + * method by the parser. + * @since 2.51 + */ + protected final Operation createMethodOperation(Position startPosition, + Position endPosition, + Position methodStartPosition, + Position methodEndPosition, + String methodName, + String methodClassType, + int bytecodeIndex, + boolean isNative) { + return new Operation(startPosition, endPosition, + methodStartPosition, methodEndPosition, + methodName, methodClassType, bytecodeIndex, + isNative); } /** @@ -502,6 +529,7 @@ private String methodDescriptor; // TODO: Add API get/set, accessed through reflection in the meantime. private String methodClassType; private Variable returnValue; + private boolean isNative; private List nextOperations; @@ -520,7 +548,7 @@ Operation(Position startPosition, Position endPosition, Position methodStartPosition, Position methodEndPosition, String methodName, String methodClassType, - int bytecodeIndex) { + int bytecodeIndex, boolean isNative) { this.startPosition = startPosition; this.endPosition = endPosition; this.bytecodeIndex = bytecodeIndex; @@ -528,6 +556,7 @@ this.methodEndPosition = methodEndPosition; this.methodName = methodName; this.methodClassType = methodClassType; + this.isNative = isNative; } synchronized void addNextOperation(Operation next) { @@ -580,6 +609,18 @@ } /** + * Indicates whether the method was determined as native by the parser. + * It can return false for native methods that are resolved + * during runtime. + * @return true when the method is determined as native by + * the parser. + * @since 2.51 + */ + public boolean isNative() { + return isNative; + } + + /** * Get the bytecode index of this operation. */ public int getBytecodeIndex() { diff -r 7578d523265c -r 5f03841799a3 api.debugger/apichanges.xml --- a/api.debugger/apichanges.xml Tue Aug 26 19:10:03 2014 +0400 +++ b/api.debugger/apichanges.xml Mon Sep 08 23:07:57 2014 +0200 @@ -501,6 +501,23 @@ + + + + A session bridge introduced to handle mixed languages debugging. + + + + + + SessionBridge class introduced. This class allows to + suggest that some debug action can be handled by a different debugging + session. The handlers can be registered via implementations of + SessionChanger interface. + + + + diff -r 7578d523265c -r 5f03841799a3 api.debugger/manifest.mf --- a/api.debugger/manifest.mf Tue Aug 26 19:10:03 2014 +0400 +++ b/api.debugger/manifest.mf Mon Sep 08 23:07:57 2014 +0200 @@ -1,5 +1,5 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.api.debugger/1 OpenIDE-Module-Localizing-Bundle: org/netbeans/api/debugger/Bundle.properties -OpenIDE-Module-Specification-Version: 1.47 +OpenIDE-Module-Specification-Version: 1.48 OpenIDE-Module-Layer: org/netbeans/api/debugger/layer.xml diff -r 7578d523265c -r 5f03841799a3 api.debugger/src/org/netbeans/api/debugger/SessionBridge.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/api.debugger/src/org/netbeans/api/debugger/SessionBridge.java Mon Sep 08 23:07:57 2014 +0200 @@ -0,0 +1,218 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ + +package org.netbeans.api.debugger; + +import java.beans.Customizer; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import org.netbeans.spi.debugger.DebuggerServiceRegistration; + +/** + * Bridge between sessions. + * Use this for mixed languages debugging. Any debug session can suggest to change + * the debugging session for a debug action. A registered implementation of + * {@link SessionChanger} can decide to change the session in order to perform + * the given action. + *

+ * In the current implementation, step into action of JPDA debugger is suggested + * for a session change only. The support can be extended according to the future + * requirements. + * + * @author Martin Entlicher + * @since 1.48 + */ +public final class SessionBridge { + + private static SessionBridge instance; + + private final Map> sessionChangers = new HashMap>(); + private final List lookupSessionChangers; + + private SessionBridge() { + Lookup lookup = new Lookup.MetaInf(null); + final List scList = lookup.lookup(null, SessionChanger.class); + ((Customizer) scList).addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + for (SessionChanger sc : lookupSessionChangers) { + removeSessionChangerListener(sc); + } + lookupSessionChangers.clear(); + for (SessionChanger sc : scList) { + lookupSessionChangers.add(sc); + addSessionChangerListener(sc); + } + } + }); + lookupSessionChangers = new ArrayList(); + for (SessionChanger sc : scList) { + lookupSessionChangers.add(sc); + addSessionChangerListener(sc); + } + } + + /** + * Get the default instance of SessionBridge. + * @return the default instance + */ + public static synchronized SessionBridge getDefault() { + if (instance == null) { + instance = new SessionBridge(); + } + return instance; + } + + /** + * Suggest a session change to perform a particular action. + * @param origin The original session suggesting the session change + * @param action An action - a constant from ActionsManager.Action_* + * @param properties Properties describing the current state of the current session before the given action. + * The actual properties are specific for the particular session type. + * @return true when the session is changed and another session + * decided to perform the given action.
+ * false when no other session would like to perform this action. + */ + public boolean suggestChange(Session origin, String action, Map properties) { + Set scs; + synchronized (sessionChangers) { + scs = sessionChangers.get(action); + } + if (scs != null) { + for (SessionChanger sc : scs) { + Session newSession = sc.changeSuggested(origin, action, properties); + if (newSession != null) { + if (DebuggerManager.getDebuggerManager().getCurrentSession() == origin) { + DebuggerManager.getDebuggerManager().setCurrentSession(newSession); + } + return true; + } + } + } + return false; + } + + /** + * Test whether there is some session changer registered for the given action. + * @param action An action - a constant from ActionsManager.Action_* + * @return true when there is some session changer registered + * for this action, false otherwise. + */ + public boolean isChangerFor(String action) { + synchronized (sessionChangers) { + Set scs = sessionChangers.get(action); + return scs != null; + } + } + + private void addSessionChangerListener(SessionChanger sc) { + Set actions = sc.getActions(); + synchronized (sessionChangers) { + for (String action : actions) { + Set scs = sessionChangers.get(action); + if (scs == null) { + sessionChangers.put(action, Collections.singleton(sc)); + } else { + if (scs.size() == 1) { + SessionChanger old = scs.iterator().next(); + scs = new CopyOnWriteArraySet(); + scs.add(old); + } + scs.add(sc); + } + } + } + } + + private void removeSessionChangerListener(SessionChanger sc) { + Set actions = sc.getActions(); + synchronized (sessionChangers) { + for (String action : actions) { + Set scs = sessionChangers.get(action); + if (scs == null) { + continue; + } + if (scs.size() == 1) { + SessionChanger old = scs.iterator().next(); + if (sc.equals(old)) { + sessionChangers.remove(action); + } + } else { + scs.remove(sc); + } + } + } + } + + /** + * Implement this interface to handle a debug session change. + * Register the implementation via {@link DebuggerServiceRegistration} annotation. + */ + public static interface SessionChanger { + + /** + * Provide the set of actions that are handled by this implementation. + * @return A set of constants from ActionsManager.Action_* + */ + Set getActions(); + + /** + * Called when a session suggests a session change for an action. + * @param origin The session suggesting the session change + * @param action The action, a constant from ActionsManager.Action_* + * @param properties Session-specific properties describing the state + * right before the given action. These are used by a new session + * to complete the given action. + * @return A new session, or null when this handler decides + * not to change the debug session for this action. + */ + Session changeSuggested(Session origin, String action, Map properties); + } + +}