execution: extract check for alternative jre; check for working directory (IDEA-77754)
[idea/community.git] / java / execution / impl / src / com / intellij / execution / application / ApplicationConfiguration.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.execution.application;
17
18 import com.intellij.diagnostic.logging.LogConfigurationPanel;
19 import com.intellij.execution.*;
20 import com.intellij.execution.configuration.EnvironmentVariablesComponent;
21 import com.intellij.execution.configurations.*;
22 import com.intellij.execution.filters.TextConsoleBuilderFactory;
23 import com.intellij.execution.junit.RefactoringListeners;
24 import com.intellij.execution.process.OSProcessHandler;
25 import com.intellij.execution.runners.ExecutionEnvironment;
26 import com.intellij.execution.util.JavaParametersUtil;
27 import com.intellij.execution.util.ProgramParametersUtil;
28 import com.intellij.openapi.components.PathMacroManager;
29 import com.intellij.openapi.diagnostic.Logger;
30 import com.intellij.openapi.extensions.Extensions;
31 import com.intellij.openapi.module.Module;
32 import com.intellij.openapi.options.SettingsEditor;
33 import com.intellij.openapi.options.SettingsEditorGroup;
34 import com.intellij.openapi.project.Project;
35 import com.intellij.openapi.util.Comparing;
36 import com.intellij.openapi.util.DefaultJDOMExternalizer;
37 import com.intellij.openapi.util.InvalidDataException;
38 import com.intellij.openapi.util.WriteExternalException;
39 import com.intellij.psi.PsiClass;
40 import com.intellij.psi.PsiElement;
41 import com.intellij.psi.util.PsiMethodUtil;
42 import com.intellij.refactoring.listeners.RefactoringElementListener;
43 import org.jdom.Element;
44 import org.jetbrains.annotations.NotNull;
45 import org.jetbrains.annotations.Nullable;
46
47 import java.util.Collection;
48 import java.util.LinkedHashMap;
49 import java.util.Map;
50
51 public class ApplicationConfiguration extends ModuleBasedConfiguration<JavaRunConfigurationModule>
52   implements CommonJavaRunConfigurationParameters, SingleClassConfiguration, RefactoringListenerProvider {
53   private static final Logger LOG = Logger.getInstance("com.intellij.execution.application.ApplicationConfiguration");
54
55   public String MAIN_CLASS_NAME;
56   public String VM_PARAMETERS;
57   public String PROGRAM_PARAMETERS;
58   public String WORKING_DIRECTORY;
59   public boolean ALTERNATIVE_JRE_PATH_ENABLED;
60   public String ALTERNATIVE_JRE_PATH;
61   public boolean ENABLE_SWING_INSPECTOR;
62
63   public String ENV_VARIABLES;
64   private Map<String,String> myEnvs = new LinkedHashMap<String, String>();
65   public boolean PASS_PARENT_ENVS = true;
66
67   public ApplicationConfiguration(final String name, final Project project, ApplicationConfigurationType applicationConfigurationType) {
68     this(name, project, applicationConfigurationType.getConfigurationFactories()[0]);
69   }
70
71   protected ApplicationConfiguration(final String name, final Project project, final ConfigurationFactory factory) {
72     super(name, new JavaRunConfigurationModule(project, true), factory);
73   }
74
75   public void setMainClass(final PsiClass psiClass) {
76     final Module originalModule = getConfigurationModule().getModule();
77     setMainClassName(JavaExecutionUtil.getRuntimeQualifiedName(psiClass));
78     setModule(JavaExecutionUtil.findModule(psiClass));
79     restoreOriginalModule(originalModule);
80   }
81
82   public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env) throws ExecutionException {
83     final JavaCommandLineState state = new JavaApplicationCommandLineState(this, env);
84     state.setConsoleBuilder(TextConsoleBuilderFactory.getInstance().createBuilder(getProject()));
85     return state;
86   }
87
88   public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
89     SettingsEditorGroup<ApplicationConfiguration> group = new SettingsEditorGroup<ApplicationConfiguration>();
90     group.addEditor(ExecutionBundle.message("run.configuration.configuration.tab.title"), new ApplicationConfigurable(getProject()));
91     JavaRunConfigurationExtensionManager.getInstance().appendEditors(this, group);
92     group.addEditor(ExecutionBundle.message("logs.tab.title"), new LogConfigurationPanel<ApplicationConfiguration>());
93     return group;
94   }
95
96   @Override
97   @Nullable
98   public String getGeneratedName() {
99     if (MAIN_CLASS_NAME == null) {
100       return null;
101     }
102     return JavaExecutionUtil.getPresentableClassName(MAIN_CLASS_NAME, getConfigurationModule());
103   }
104
105   public void setGeneratedName() {
106     setName(getGeneratedName());
107   }
108
109   public RefactoringElementListener getRefactoringElementListener(final PsiElement element) {
110     final RefactoringElementListener listener = RefactoringListeners.
111       getClassOrPackageListener(element, new RefactoringListeners.SingleClassConfigurationAccessor(this));
112     return RunConfigurationExtension.wrapRefactoringElementListener(element, this, listener);
113   }
114
115   @Nullable
116   public PsiClass getMainClass() {
117     return getConfigurationModule().findClass(MAIN_CLASS_NAME);
118   }
119
120   public boolean isGeneratedName() {
121     if (MAIN_CLASS_NAME == null || MAIN_CLASS_NAME.length() == 0) {
122       return JavaExecutionUtil.isNewName(getName());
123     }
124     return Comparing.equal(getName(), getGeneratedName());
125   }
126
127   public String suggestedName() {
128     if (MAIN_CLASS_NAME == null || MAIN_CLASS_NAME.length() == 0) {
129       return getName();
130     }
131     return ProgramRunnerUtil.shortenName(JavaExecutionUtil.getShortClassName(MAIN_CLASS_NAME), 6) + ".main()";
132   }
133
134   public void setMainClassName(final String qualifiedName) {
135     final boolean generatedName = isGeneratedName();
136     MAIN_CLASS_NAME = qualifiedName;
137     if (generatedName) setGeneratedName();
138   }
139
140   public void checkConfiguration() throws RuntimeConfigurationException {
141     JavaParametersUtil.checkAlternativeJRE(this);
142     final JavaRunConfigurationModule configurationModule = getConfigurationModule();
143     final PsiClass psiClass = configurationModule.checkModuleAndClassName(MAIN_CLASS_NAME, ExecutionBundle.message("no.main.class.specified.error.text"));
144     if (!PsiMethodUtil.hasMainMethod(psiClass)) {
145       throw new RuntimeConfigurationWarning(ExecutionBundle.message("main.method.not.found.in.class.error.message", MAIN_CLASS_NAME));
146     }
147     ProgramParametersUtil.checkWorkingDirectoryExist(this, getProject(), configurationModule.getModule());
148     JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
149   }
150
151   public void setVMParameters(String value) {
152     VM_PARAMETERS = value;
153   }
154
155   public String getVMParameters() {
156     return VM_PARAMETERS;
157   }
158
159   public void setProgramParameters(String value) {
160     PROGRAM_PARAMETERS = value;
161   }
162
163   public String getProgramParameters() {
164     return PROGRAM_PARAMETERS;
165   }
166
167   public void setWorkingDirectory(String value) {
168     WORKING_DIRECTORY = ExternalizablePath.urlValue(value);
169   }
170
171   public String getWorkingDirectory() {
172     return ExternalizablePath.localPathValue(WORKING_DIRECTORY);
173   }
174
175   public void setPassParentEnvs(boolean passParentEnvs) {
176     PASS_PARENT_ENVS = passParentEnvs;
177   }
178
179   @NotNull
180   public Map<String, String> getEnvs() {
181     return myEnvs;
182   }
183
184   public void setEnvs(@NotNull final Map<String, String> envs) {
185     this.myEnvs = envs;
186   }
187
188   public boolean isPassParentEnvs() {
189     return PASS_PARENT_ENVS;
190   }
191
192   @Nullable
193   public String getRunClass() {
194     return MAIN_CLASS_NAME;
195   }
196
197   @Nullable
198   public String getPackage() {
199     return null;
200   }
201
202   public boolean isAlternativeJrePathEnabled() {
203      return ALTERNATIVE_JRE_PATH_ENABLED;
204    }
205
206    public void setAlternativeJrePathEnabled(boolean enabled) {
207      this.ALTERNATIVE_JRE_PATH_ENABLED = enabled;
208    }
209
210    public String getAlternativeJrePath() {
211      return ALTERNATIVE_JRE_PATH;
212    }
213
214    public void setAlternativeJrePath(String path) {
215      this.ALTERNATIVE_JRE_PATH = path;
216    }
217
218   public Collection<Module> getValidModules() {
219     return JavaRunConfigurationModule.getModulesForClass(getProject(), MAIN_CLASS_NAME);
220   }
221
222   protected ModuleBasedConfiguration createInstance() {
223     return new ApplicationConfiguration(getName(), getProject(), ApplicationConfigurationType.getInstance());
224   }
225
226   public void readExternal(final Element element) throws InvalidDataException {
227     PathMacroManager.getInstance(getProject()).expandPaths(element);
228     super.readExternal(element);
229     JavaRunConfigurationExtensionManager.getInstance().readExternal(this, element);
230     DefaultJDOMExternalizer.readExternal(this, element);
231     readModule(element);
232     EnvironmentVariablesComponent.readExternal(element, getEnvs());
233   }
234
235   public void writeExternal(final Element element) throws WriteExternalException {
236     super.writeExternal(element);
237     JavaRunConfigurationExtensionManager.getInstance().writeExternal(this, element);
238     DefaultJDOMExternalizer.writeExternal(this, element);
239     writeModule(element);
240     EnvironmentVariablesComponent.writeExternal(element, getEnvs());
241     PathMacroManager.getInstance(getProject()).collapsePathsRecursively(element);
242   }
243
244   public static class JavaApplicationCommandLineState extends JavaCommandLineState {
245
246     private final ApplicationConfiguration myConfiguration;
247
248     public JavaApplicationCommandLineState(@NotNull final ApplicationConfiguration configuration,
249                                            final ExecutionEnvironment environment) {
250       super(environment);
251       myConfiguration = configuration;
252     }
253
254     protected JavaParameters createJavaParameters() throws ExecutionException {
255       final JavaParameters params = new JavaParameters();
256       final JavaRunConfigurationModule module = myConfiguration.getConfigurationModule();
257       
258       final int classPathType = JavaParametersUtil.getClasspathType(module,
259                                                                     myConfiguration.MAIN_CLASS_NAME, 
260                                                                     false);
261       final String jreHome = myConfiguration.ALTERNATIVE_JRE_PATH_ENABLED ? myConfiguration.ALTERNATIVE_JRE_PATH 
262                                                                           : null;
263       JavaParametersUtil.configureModule(module, params, classPathType, jreHome);
264       JavaParametersUtil.configureConfiguration(params, myConfiguration);
265
266       params.setMainClass(myConfiguration.MAIN_CLASS_NAME);
267       for(RunConfigurationExtension ext: Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
268         ext.updateJavaParameters(myConfiguration, params, getRunnerSettings());
269       }
270
271       return params;
272     }
273
274     @NotNull
275     @Override
276     protected OSProcessHandler startProcess() throws ExecutionException {
277       final OSProcessHandler handler = super.startProcess();
278       RunnerSettings runnerSettings = getRunnerSettings();
279       JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(myConfiguration, handler, runnerSettings);
280       return handler;
281     }
282
283     protected ApplicationConfiguration getConfiguration() {
284       return myConfiguration;
285     }
286   }
287 }