Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion java/java.file.launcher/nbproject/project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.

javac.source=1.8
javac.release=17
cp.extra=${tools.jar}
requires.nb.javac=true
javac.compilerargs=-Xlint -Xlint:-serial
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import java.util.logging.Logger;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.netbeans.api.java.platform.JavaPlatformManager;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.modules.java.file.launcher.queries.MultiSourceRootProvider;
import org.netbeans.modules.java.file.launcher.spi.SingleFileOptionsQueryImplementation;
Expand All @@ -49,6 +49,7 @@
public final class SingleSourceFileUtil {
public static final Logger LOG = Logger.getLogger(SingleSourceFileUtil.class.getPackage().getName());

// TODO this checks the runtime JDK of NB!
public static int findJavaVersion() throws NumberFormatException {
// JEP-330 is supported only on JDK-11 and above.
String javaVersion = System.getProperty("java.specification.version"); //NOI18N
Expand All @@ -59,7 +60,9 @@ public static int findJavaVersion() throws NumberFormatException {
return version;
}

// synced with JavaNode
public static final String FILE_ARGUMENTS = "single_file_run_arguments"; //NOI18N
public static final String FILE_JDK = "single_file_run_jdk"; //NOI18N
public static final String FILE_VM_OPTIONS = "single_file_vm_options"; //NOI18N

public static FileObject getJavaFileWithoutProjectFromLookup(Lookup lookup) {
Expand Down Expand Up @@ -101,8 +104,8 @@ public static boolean isSupportedFile(FileObject file) {
return false;
}
}
public static Process compileJavaSource(FileObject fileObject) {
FileObject javac = JavaPlatformManager.getDefault().getDefaultPlatform().findTool("javac"); //NOI18N
public static Process compileJavaSource(FileObject fileObject, JavaPlatform jdk) {
FileObject javac = jdk.findTool("javac"); //NOI18N
File javacFile = FileUtil.toFile(javac);
String javacPath = javacFile.getAbsolutePath();
List<String> compileCommandList = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import java.util.List;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.extexecution.base.ExplicitProcessParameters;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.java.platform.JavaPlatformManager;
import org.netbeans.modules.java.file.launcher.SingleSourceFileUtil;
import org.openide.filesystems.FileObject;
Expand Down Expand Up @@ -59,16 +61,18 @@ private Process setupProcess(String port) throws InterruptedException {
try {
boolean compile = SingleSourceFileUtil.findJavaVersion() < 11 || SingleSourceFileUtil.hasClassSibling(fileObject);

JavaPlatform jdk = readRunJdkFromAttribute(fileObject);

if (compile) {
Process p = SingleSourceFileUtil.compileJavaSource(fileObject);
Process p = SingleSourceFileUtil.compileJavaSource(fileObject, jdk);
if (p.waitFor() != 0) {
return p;
}
}

List<String> commandsList = new ArrayList<>();

FileObject java = JavaPlatformManager.getDefault().getDefaultPlatform().findTool("java"); //NOI18N
FileObject java = jdk.findTool("java"); //NOI18N
File javaFile = FileUtil.toFile(java);
String javaPath = javaFile.getAbsolutePath();
URI cwd = SingleSourceFileUtil.getOptionsFor(fileObject).getWorkDirectory();
Expand Down Expand Up @@ -123,6 +127,19 @@ private Process setupProcess(String port) throws InterruptedException {
return null;
}

private static JavaPlatform readRunJdkFromAttribute(FileObject fo) {
String runJDKAttribute = fo.getAttribute(SingleSourceFileUtil.FILE_JDK) instanceof String str ? str : null;
if (runJDKAttribute != null && !runJDKAttribute.isBlank()) {
for (JavaPlatform jdk : JavaPlatformManager.getDefault().getInstalledPlatforms()) {
if (runJDKAttribute.equals(jdk.getDisplayName())) {
return jdk;
}
}
Logger.getLogger(LaunchProcess.class.getName()).log(Level.WARNING, "Unknown JDK: [{0}]", runJDKAttribute);
}
return JavaPlatformManager.getDefault().getDefaultPlatform();
}

private static List<String> readArgumentsFromAttribute(FileObject fileObject, String attributeName) {
Object argumentsObject = fileObject.getAttribute(attributeName);
if (!(argumentsObject instanceof String)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ LBL_JavaNode_sheet_classpaths=Classpaths
HINT_JavaNode_sheet_classpaths=Effective classpaths used by the IDE for this source file, for example as reported by a project. Sources displayed where applicable.
LBL_JavaNode_sheet_classfile=Class File
HINT_JavaNode_sheet_classfile=Java Class File Attributes
PROP_JavaNode_singlefile_jdk=JDK
HINT_JavaNode_singlefile_jdk=JDK used to run the file.
PROP_JavaNode_singlefile_arguments=Program Arguments
HINT_JavaNode_singlefile_arguments=Arguments passed to the main method while running the file.
PROP_JavaNode_singlefile_options=VM Options
HINT_JavaNode_singlefile_options=VM Options to be considered while running the file.
PROP_JavaNode_classfile_version=Classfile Version
HINT_JavaNode_classfile_version=The Java API and Language Level of this class file
PROP_JavaNode_compile_classpath=Compile Classpath
Expand Down
198 changes: 131 additions & 67 deletions java/java.source/src/org/netbeans/modules/java/JavaNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import java.awt.Component;
import org.netbeans.api.java.source.support.ErrorAwareTreeScanner;
import java.awt.Image;
import java.beans.PropertyChangeListener;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorSupport;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
Expand All @@ -37,24 +41,27 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HexFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javax.lang.model.element.Modifier;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.platform.JavaPlatformManager;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.ModificationResult;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.queries.FileBuiltQuery;
Expand All @@ -63,14 +70,11 @@
import org.netbeans.modules.classfile.ClassFile;
import org.netbeans.modules.classfile.InvalidClassFormatException;
import org.netbeans.modules.java.source.usages.ExecutableFilesIndex;
import org.netbeans.modules.parsing.api.ResultIterator;
import org.netbeans.modules.parsing.api.Source;
import org.netbeans.modules.parsing.api.UserTask;
import org.netbeans.modules.parsing.spi.ParseException;
import org.netbeans.spi.java.loaders.RenameHandler;
import org.openide.filesystems.*;
import org.openide.loaders.DataNode;
import org.openide.loaders.DataObject;
import org.openide.modules.SpecificationVersion;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.PropertySupport;
Expand Down Expand Up @@ -103,7 +107,9 @@ public final class JavaNode extends DataNode implements ChangeListener {
private static final String ANNOTATION_ICON_BASE = "org/netbeans/modules/java/resources/annotation_file.png"; //NOI18N
private static final String EXECUTABLE_BADGE_URL = "org/netbeans/modules/java/resources/executable-badge.png"; //NOI18N
private static final String NEEDS_COMPILE_BADGE_URL = "org/netbeans/modules/java/resources/needs-compile.png"; //NOI18N
// synced with org.netbeans.modules.java.file.launcher.SingleSourceFileUtil
private static final String FILE_ARGUMENTS = "single_file_run_arguments"; //NOI18N
private static final String FILE_JDK = "single_file_run_jdk"; //NOI18N
private static final String FILE_VM_OPTIONS = "single_file_vm_options"; //NOI18N

private static final Map<String,Image> IMAGE_CACHE = new ConcurrentHashMap<>();
Expand Down Expand Up @@ -232,72 +238,16 @@ protected final Sheet createSheet () {
DataObject dObj = super.getDataObject();
// If any of the parent folders is a project, user won't have the option to specify these attributes to the java files.
if (parentProject == null) {
Node.Property arguments = new PropertySupport.ReadWrite<String> (
"runFileArguments", // NOI18N
String.class,
"Arguments",
"Arguments passed to the main method while running the file."
) {
@Override
public String getValue () {
Object arguments = dObj.getPrimaryFile().getAttribute(FILE_ARGUMENTS);
return arguments != null ? (String) arguments : "";
}

@Override
public void setValue (String o) {
try {
dObj.getPrimaryFile().setAttribute(FILE_ARGUMENTS, o);
} catch (IOException ex) {
LOG.log(
Level.WARNING,
"Java File does not exist : {0}", //NOI18N
dObj.getPrimaryFile().getName());
}
}
};
Node.Property vmOptions = new PropertySupport.ReadWrite<String> (
"runFileVMOptions", // NOI18N
String.class,
"VM Options",
"VM Options to be considered while running the file."
) {
@Override
public String getValue () {
Object vmOptions = dObj.getPrimaryFile().getAttribute(FILE_VM_OPTIONS);
return vmOptions != null ? (String) vmOptions : "";
}

@Override
public void setValue(String o) {
try {
dObj.getPrimaryFile().setAttribute(FILE_VM_OPTIONS, o);
Source s = Source.create(dObj.getPrimaryFile());
ModificationResult result = ModificationResult.runModificationTask(List.of(s), new UserTask() {

@Override
public void run(ResultIterator resultIterator) {
}
});
result.commit();
} catch (IOException | ParseException ex) {
LOG.log(
Level.WARNING,
"Java File does not exist : {0}", //NOI18N
dObj.getPrimaryFile().getName());
}
}
};
Sheet.Set ss = new Sheet.Set();
ss.setName("runFileArguments"); // NOI18N
ss.setDisplayName(getMessage(JavaNode.class, "LBL_JavaNode_without_project_run"));
ss.setDisplayName(getMessage(JavaNode.class, "LBL_JavaNode_without_project_run")); // NOI18N
ss.setShortDescription("Run the file's source code.");
ss.put (arguments);
ss.put (vmOptions);
ss.put(new RunFileJDKProperty(dObj));
ss.put(new JavaFileAttributeProperty(dObj, FILE_ARGUMENTS, "runFileArguments", "singlefile_arguments")); // NOI18N
ss.put(new JavaFileAttributeProperty(dObj, FILE_VM_OPTIONS, "runFileVMOptions", "singlefile_options")); // NOI18N
sheet.put(ss);
}



@SuppressWarnings("LocalVariableHidesMemberVariable")
PropertySet[] propertySets = sheet.toArray();

Expand Down Expand Up @@ -429,6 +379,120 @@ public String getValue() {
}
}

private static final class RunFileJDKProperty extends PropertySupport.ReadWrite<String> {

private final PropertyEditorSupport jdkPicker = new JDKPicker();
private final DataObject dObj;

public RunFileJDKProperty(DataObject dObj) {
super("runFileJDK", String.class, // NOI18N
getMessage(JavaNode.class, "PROP_JavaNode_singlefile_jdk"), // NOI18N
getMessage(JavaNode.class, "HINT_JavaNode_singlefile_jdk")); // NOI18N
this.dObj = dObj;
}

@Override
public String getValue() {
return dObj.getPrimaryFile().getAttribute(FILE_JDK) instanceof String jdk ? jdk : "";
}

@Override
public void setValue(String text) {
try {
dObj.getPrimaryFile().setAttribute(FILE_JDK, text);
} catch (IOException ex) {
LOG.log(Level.WARNING, "Java File does not exist : {0}", dObj.getPrimaryFile().getName()); //NOI18N
}
}

@Override
public PropertyEditor getPropertyEditor() {
return jdkPicker;
}

// inline combobox for jdk property
private static final class JDKPicker extends PropertyEditorSupport {

private final JComboBox jdkCombo = new JComboBox();
private final PropertyChangeListener modelUpdater = e -> initModel();
private String[] jdks;

public JDKPicker() {
initModel();
jdkCombo.addActionListener(e -> super.setValue(jdkCombo.getSelectedItem()));
JavaPlatformManager jdkman = JavaPlatformManager.getDefault();
jdkman.addPropertyChangeListener(WeakListeners.propertyChange(modelUpdater, jdkman));
}

private void initModel() {
jdks = Stream.of(JavaPlatformManager.getDefault().getInstalledPlatforms())
.filter(jdk -> isCompatible(jdk.getSpecification().getVersion()))
.map(jdk -> jdk.getDisplayName())
.sorted(Comparator.reverseOrder())
.toArray(String[]::new);
jdkCombo.setModel(new DefaultComboBoxModel(jdks));
}

private static boolean isCompatible(SpecificationVersion jdkVerison) {
try {
return Integer.parseInt(jdkVerison.toString()) >= 11;
} catch (NumberFormatException ignore) {}
return false;
}

@Override
public void setAsText(String text) throws IllegalArgumentException {
jdkCombo.setSelectedItem(text);
}

@Override
public void setValue(Object value) {
jdkCombo.setSelectedItem(value);
super.setValue(value);
}

@Override
@SuppressWarnings("ReturnOfCollectionOrArrayField")
public String[] getTags() {
return jdks;
}

@Override
public Component getCustomEditor() {
return jdkCombo;
}

}

}

// editable file attribute
private static final class JavaFileAttributeProperty extends PropertySupport.ReadWrite<String> {

private final String attribute;
private final DataObject dObj;

public JavaFileAttributeProperty(DataObject dObj, String attribute, String name, String msgKeyPart) {
super(name, String.class, getMessage(JavaNode.class, "PROP_JavaNode_" + msgKeyPart), getMessage(JavaNode.class, "HINT_JavaNode_" + msgKeyPart)); // NOI18N
this.dObj = dObj;
this.attribute = attribute;
}

@Override
public String getValue() {
return dObj.getPrimaryFile().getAttribute(attribute) instanceof String val ? val : "";
}

@Override
public void setValue(String o) {
try {
dObj.getPrimaryFile().setAttribute(attribute, o);
} catch (IOException ex) {
LOG.log(Level.WARNING, "Java File does not exist : {0}", dObj.getPrimaryFile().getName()); //NOI18N
}
}
}

@Override
public void stateChanged(ChangeEvent e) {
WORKER.post(new BuildStatusTask(this));
Expand Down