| /*=============================================================================# |
| # Copyright (c) 2008, 2021 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.internal.r.console.ui.launching; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; |
| import org.eclipse.jdt.debug.ui.launchConfigurations.JavaJRETab; |
| import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; |
| import org.eclipse.jdt.launching.IVMInstall; |
| import org.eclipse.jdt.launching.IVMInstall3; |
| import org.eclipse.jdt.launching.JavaRuntime; |
| import org.eclipse.jdt.launching.VMStandin; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Group; |
| import org.eclipse.swt.widgets.Label; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.collections.ImIdentitySet; |
| |
| import org.eclipse.statet.ecommons.debug.ui.config.InputArgumentsComposite; |
| import org.eclipse.statet.ecommons.debug.ui.config.LaunchConfigUtils; |
| import org.eclipse.statet.ecommons.preferences.core.PreferenceSetService; |
| import org.eclipse.statet.ecommons.preferences.core.util.PreferenceUtils; |
| import org.eclipse.statet.ecommons.ui.util.LayoutUtils; |
| import org.eclipse.statet.ecommons.ui.util.UIAccess; |
| |
| import org.eclipse.statet.internal.r.console.ui.Messages; |
| import org.eclipse.statet.internal.r.console.ui.RConsoleUIPlugin; |
| import org.eclipse.statet.r.core.renv.IREnvManager; |
| import org.eclipse.statet.r.launching.ui.REnvTab; |
| import org.eclipse.statet.rj.renv.core.REnv; |
| import org.eclipse.statet.rj.renv.core.REnvConfiguration; |
| |
| |
| /** |
| * Adds: |
| * <li>Optional requirement/validation of JRE</li> |
| * <li>VM Arguments</li> |
| */ |
| class ExtJavaJRETab extends JavaJRETab implements PreferenceSetService.ChangeListener { |
| |
| |
| private boolean is32(final String arch) { |
| return (arch.equals(Platform.ARCH_X86) |
| || arch.equals("i386") || arch.equals("i586") || arch.equals("i686") ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| private boolean is64(final String arch) { |
| return (arch.equals(Platform.ARCH_X86_64) |
| || arch.equals("amd64") ); //$NON-NLS-1$ |
| } |
| |
| private final ImIdentitySet<String> PREF_QUALIFIERS= ImCollections.newIdentitySet( |
| IREnvManager.PREF_QUALIFIER ); |
| |
| |
| private final RConsoleMainTab mainTab; |
| private final REnvTab rEnvTab; |
| |
| private InputArgumentsComposite vmArgsControl; |
| |
| private final boolean enableVMArchCheck; |
| private IVMInstall lastCheckedVM; |
| private int lastCheckedVMBits; |
| private int lastCheckedRBits; |
| private boolean validInBackground; |
| |
| |
| public ExtJavaJRETab(final RConsoleMainTab mainTab, final REnvTab renvTab) { |
| this.mainTab= mainTab; |
| this.rEnvTab= renvTab; |
| |
| PreferenceUtils.getInstancePrefs().addPreferenceSetListener(this, this.PREF_QUALIFIERS); |
| |
| this.enableVMArchCheck= ((Platform.getOS().startsWith("win") || Platform.getOS().equals(Platform.OS_LINUX)) //$NON-NLS-1$ |
| && (Platform.getOSArch().startsWith("x86") || Platform.getOSArch().startsWith("amd64")) ); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| |
| @Override |
| public void createControl(final Composite parent) { |
| super.createControl(parent); |
| |
| final Composite tabHolder= getDynamicTabHolder(); |
| final Composite composite= tabHolder.getParent(); |
| final GridLayout layout= (GridLayout) composite.getLayout(); |
| |
| tabHolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, layout.numColumns, 1)); |
| |
| final Composite extComposite= new Composite(composite, SWT.NONE); |
| final GridLayout extLayout= new GridLayout(); |
| extLayout.marginHeight= 0; |
| extComposite.setLayout(extLayout); |
| extComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, layout.numColumns, 1)); |
| final Group group= new Group(extComposite, SWT.NONE); |
| group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); |
| group.setLayout(LayoutUtils.newGroupGrid(1)); |
| group.setText(Messages.JavaJRE_Tab_VMConfig_group); |
| |
| this.vmArgsControl= new InputArgumentsComposite(group, Messages.JavaJRE_Tab_VMArguments_label); |
| this.vmArgsControl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); |
| this.vmArgsControl.getTextControl().addModifyListener(new ModifyListener() { |
| @Override |
| public void modifyText(final ModifyEvent e) { |
| updateLaunchConfigurationDialog(); |
| } |
| }); |
| |
| final Label note= new Label(group, SWT.WRAP); |
| note.setText(this.vmArgsControl.getNoteText()); |
| note.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); |
| |
| Dialog.applyDialogFont(extComposite); |
| } |
| |
| @Override |
| protected void loadDynamicJREArea() { |
| super.loadDynamicJREArea(); |
| |
| final Composite tabHolder= getDynamicTabHolder(); |
| tabHolder.getParent().layout(new Control[] { tabHolder }); |
| } |
| |
| @Override |
| public void preferenceChanged(final PreferenceSetService.ChangeEvent event) { |
| if (event.contains(IREnvManager.PREF_QUALIFIER)) { |
| UIAccess.getDisplay().syncExec(new Runnable() { |
| @Override |
| public void run() { |
| final int previous= ExtJavaJRETab.this.lastCheckedRBits; |
| updateRBits(); |
| if (previous != ExtJavaJRETab.this.lastCheckedRBits |
| && UIAccess.isOkToUse(getControl()) |
| && LaunchConfigUtils.isActiveTabGroup(getLaunchConfigurationDialog(), ExtJavaJRETab.this)) { |
| getLaunchConfigurationDialog().updateMessage(); |
| getLaunchConfigurationDialog().updateButtons(); |
| } |
| } |
| }); |
| } |
| } |
| |
| @Override |
| public void dispose() { |
| PreferenceUtils.getInstancePrefs().removePreferenceSetListener(this); |
| |
| super.dispose(); |
| } |
| |
| |
| @Override |
| public boolean isValid(final ILaunchConfiguration config) { |
| if (this.enableVMArchCheck) { |
| if (this.validInBackground) { |
| scheduleUpdateJob(); |
| return false; |
| } |
| final RConsoleType type= this.mainTab.getSelectedType(); |
| if (type == null || !type.requireJRE()) { |
| setErrorMessage(null); |
| setMessage(null); |
| return true; |
| } |
| if (!super.isValid(config)) { |
| return false; |
| } |
| // try to check compatibility |
| |
| updateRBits(); |
| if (this.lastCheckedRBits == -1) { |
| // check not necessary |
| return true; |
| } |
| |
| IVMInstall jre= null; |
| try { |
| jre= JavaRuntime.computeVMInstall(config); |
| } |
| catch (final CoreException e) { |
| } |
| if (jre instanceof VMStandin) { |
| jre= ((VMStandin) jre).convertToRealVM(); |
| } |
| if (jre != null && this.lastCheckedVM != jre) { |
| this.lastCheckedVM= jre; |
| updateVMBits(); |
| } |
| if (jre == null || this.lastCheckedVMBits == -1) { |
| // check failed technically |
| return true; |
| } |
| if (this.lastCheckedVMBits == this.lastCheckedRBits) { |
| return true; |
| } |
| else { |
| setErrorMessage(NLS.bind(Messages.JavaJRE_RCompatibility_error_DifferentBits_message, this.lastCheckedRBits, this.lastCheckedVMBits)); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private void updateRBits() { |
| this.lastCheckedRBits= -1; |
| final REnv rEnv= this.rEnvTab.getSelectedEnv(); |
| if (rEnv == null) { |
| return; |
| } |
| final REnvConfiguration rEnvConfig= rEnv.get(REnvConfiguration.class); |
| if (rEnvConfig == null) { |
| return; |
| } |
| final String arch= rEnvConfig.getRArch(); |
| if (arch != null && arch.length() > 0) { |
| if (is32(arch)) { |
| this.lastCheckedRBits= 32; |
| } |
| else if (is64(arch)) { |
| this.lastCheckedRBits= 64; |
| } |
| } |
| } |
| |
| private void updateVMBits() { |
| this.lastCheckedVMBits= -1; |
| if (this.lastCheckedVM instanceof IVMInstall3) { |
| this.validInBackground= true; |
| try { |
| getLaunchConfigurationDialog().run(true, true, new IRunnableWithProgress() { |
| @Override |
| public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { |
| final String[] propertyNames= new String[] { "os.arch", "java.vm.name", "sun.arch.data.model", "com.ibm.vm.bitmode" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| try { |
| final Map<String, String> properties= ((IVMInstall3) ExtJavaJRETab.this.lastCheckedVM).evaluateSystemProperties(propertyNames, monitor); |
| |
| { // try known os.arch |
| final String p= properties.get("os.arch"); //$NON-NLS-1$ |
| if (p != null && p.length() > 0) { |
| if (is32(p)) { |
| ExtJavaJRETab.this.lastCheckedVMBits= 32; |
| return; |
| } |
| else if (is64(p)) { |
| ExtJavaJRETab.this.lastCheckedVMBits= 64; |
| return; |
| } |
| } |
| } |
| } |
| catch (final CoreException e) { |
| throw new InvocationTargetException(e); |
| } |
| } |
| }); |
| } |
| catch (final InvocationTargetException e) { |
| RConsoleUIPlugin.logError( |
| "An error when trying to fetch VM properties for JRE validation.", //$NON-NLS-1$ |
| e.getTargetException() ); |
| } |
| catch (final InterruptedException e) { |
| } |
| finally { |
| this.validInBackground= false; |
| } |
| } |
| } |
| |
| |
| @Override |
| public void initializeFrom(final ILaunchConfiguration configuration) { |
| super.initializeFrom(configuration); |
| |
| String vmArgs= null; |
| try { |
| vmArgs= configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, (String) null); |
| } |
| catch (final CoreException e) { |
| } |
| this.vmArgsControl.getTextControl().setText(vmArgs != null ? vmArgs : ""); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public void performApply(final ILaunchConfigurationWorkingCopy configuration) { |
| super.performApply(configuration); |
| |
| final String vmArgs= this.vmArgsControl.getTextControl().getText(); |
| configuration.setAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, |
| (vmArgs.length() > 0) ? vmArgs : (String) null); |
| } |
| |
| @Override |
| protected long getUpdateJobDelay() { |
| return 400; |
| } |
| |
| } |