Make MODULE_FILE optional
[idea/community.git] / platform / lang-impl / src / com / intellij / execution / impl / ModuleRunConfigurationManager.java
1 /*
2  * Copyright 2000-2016 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.impl;
17
18 import com.intellij.ProjectTopics;
19 import com.intellij.execution.RunnerAndConfigurationSettings;
20 import com.intellij.execution.configurations.ModuleBasedConfiguration;
21 import com.intellij.execution.configurations.RunConfiguration;
22 import com.intellij.openapi.components.PersistentStateComponent;
23 import com.intellij.openapi.components.State;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.module.Module;
26 import com.intellij.openapi.module.ModuleComponent;
27 import com.intellij.openapi.project.ModuleAdapter;
28 import com.intellij.openapi.project.Project;
29 import com.intellij.openapi.util.Comparing;
30 import com.intellij.openapi.util.Condition;
31 import com.intellij.openapi.util.InvalidDataException;
32 import com.intellij.openapi.util.WriteExternalException;
33 import com.intellij.util.containers.ContainerUtil;
34 import com.intellij.util.containers.HashSet;
35 import org.jdom.Element;
36 import org.jetbrains.annotations.NonNls;
37 import org.jetbrains.annotations.NotNull;
38 import org.jetbrains.annotations.Nullable;
39
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.List;
43 import java.util.Set;
44
45 @State(name = ModuleRunConfigurationManager.COMPONENT_NAME)
46 public final class ModuleRunConfigurationManager extends ModuleAdapter implements ModuleComponent, PersistentStateComponent<Element> {
47   private static final Logger LOG = Logger.getInstance(ModuleRunConfigurationManager.class);
48   @NonNls static final String COMPONENT_NAME = "ModuleRunConfigurationManager";
49   @NotNull
50   private final Condition<RunnerAndConfigurationSettings> myModuleConfigCondition = new Condition<RunnerAndConfigurationSettings>() {
51     @Override
52     public boolean value(@Nullable RunnerAndConfigurationSettings settings) {
53       return settings != null && usesMyModule(settings.getConfiguration());
54     }
55   };
56   @NotNull
57   private final Module myModule;
58   @NotNull
59   private final RunManagerImpl myManager;
60   @Nullable
61   private List<Element> myUnloadedElements = null;
62
63   public ModuleRunConfigurationManager(@NotNull final Module module, @NotNull final RunManagerImpl runManager) {
64     myModule = module;
65     myManager = runManager;
66   }
67
68   @Override
69   public void projectOpened() {
70   }
71
72   @Override
73   public void projectClosed() {
74   }
75
76   @Override
77   public void moduleAdded() {
78   }
79
80   @Override
81   public void initComponent() {
82     LOG.debug("initComponent(" + myModule + ")");
83     myModule.getMessageBus().connect(myModule).subscribe(ProjectTopics.MODULES, this);
84   }
85
86   @Override
87   public void disposeComponent() {
88   }
89
90   @NotNull
91   @Override
92   public String getComponentName() {
93     return COMPONENT_NAME;
94   }
95
96   @Nullable
97   @Override
98   public Element getState() {
99     try {
100       final Element e = new Element("state");
101       writeExternal(e);
102       return e;
103     }
104     catch (WriteExternalException e1) {
105       LOG.error(e1);
106       return null;
107     }
108   }
109
110   @Override
111   public void loadState(Element state) {
112     try {
113       readExternal(state);
114     }
115     catch (InvalidDataException e) {
116       LOG.error(e);
117     }
118   }
119
120   @NotNull
121   private Collection<? extends RunnerAndConfigurationSettings> getModuleRunConfigurationSettings() {
122     return ContainerUtil.filter(myManager.getConfigurationSettings(), myModuleConfigCondition);
123   }
124
125   private boolean usesMyModule(RunConfiguration config) {
126     return config instanceof ModuleBasedConfiguration
127            && myModule.equals(((ModuleBasedConfiguration)config).getConfigurationModule().getModule());
128   }
129
130   public void writeExternal(@NotNull final Element element) throws WriteExternalException {
131     LOG.debug("writeExternal(" + myModule + ")");
132     for (final RunnerAndConfigurationSettings settings : getModuleRunConfigurationSettings()) {
133       myManager.addConfigurationElement(element, settings);
134     }
135     if (myUnloadedElements != null) {
136       for (final Element unloadedElement : myUnloadedElements) {
137         element.addContent(unloadedElement.clone());
138       }
139     }
140   }
141
142   public void readExternal(@NotNull final Element element) throws InvalidDataException {
143     LOG.debug("readExternal(" + myModule + ")");
144     myUnloadedElements = null;
145     final Set<String> existing = new HashSet<String>();
146
147     final List children = element.getChildren();
148     for (final Object child : children) {
149       final RunnerAndConfigurationSettings configuration = myManager.loadConfiguration((Element)child, true);
150       if (configuration == null && Comparing.strEqual(element.getName(), RunManagerImpl.CONFIGURATION)) {
151         if (myUnloadedElements == null) myUnloadedElements = new ArrayList<Element>(2);
152         myUnloadedElements.add(element);
153       }
154
155       if (configuration != null) {
156         existing.add(configuration.getUniqueID());
157       }
158     }
159
160     for (final RunConfiguration configuration : myManager.getAllConfigurationsList()) {
161       if (!usesMyModule(configuration)) {
162         RunnerAndConfigurationSettings settings = myManager.getSettings(configuration);
163         if (settings != null)
164           existing.add(settings.getUniqueID());
165       }
166     }
167     myManager.removeNotExistingSharedConfigurations(existing);
168
169     // IDEA-60004: configs may never be sorted before write, so call it manually after shared configs read
170     myManager.setOrdered(false);
171     myManager.getSortedConfigurations();
172   }
173
174   @Override
175   public void beforeModuleRemoved(@NotNull Project project, @NotNull Module module) {
176     if (myModule.equals(module)) {
177       LOG.debug("time to remove something from project (" + project + ")");
178       for (final RunnerAndConfigurationSettings settings : getModuleRunConfigurationSettings()) {
179         myManager.removeConfiguration(settings);
180       }
181     }
182   }
183 }