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