ES: extract ProjectDataManager interface to API module

This commit is contained in:
Vladislav.Soroka
2017-04-14 14:45:20 +03:00
parent 86360b368d
commit 31dd179c80
5 changed files with 537 additions and 364 deletions
@@ -0,0 +1,67 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.externalSystem.service.project;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataService;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* Aggregates all {@link ProjectDataService#EP_NAME registered data services}
* and provides entry points for project data management.
*
* @author Vladislav Soroka
* @since 4/16/13 11:38 AM
*/
public interface ProjectDataManager {
static ProjectDataManager getInstance() {
return ServiceManager.getService(ProjectDataManager.class);
}
@SuppressWarnings("unchecked")
void importData(@NotNull Collection<DataNode<?>> nodes,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous);
<T> void importData(@NotNull Collection<DataNode<T>> nodes, @NotNull Project project, boolean synchronous);
<T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous);
<T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
boolean synchronous);
void ensureTheDataIsReadyToUse(@Nullable DataNode dataNode);
@Nullable
ExternalProjectInfo getExternalProjectData(@NotNull Project project,
@NotNull ProjectSystemId projectSystemId,
@NotNull String externalProjectPath);
@NotNull
Collection<ExternalProjectInfo> getExternalProjectsData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,394 +15,102 @@
*/
package com.intellij.openapi.externalSystem.service.project.manage;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.*;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.Key;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl;
import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Consumer;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.util.containers.ContainerUtil.map2Array;
import java.util.Collection;
/**
* Aggregates all {@link ProjectDataService#EP_NAME registered data services} and provides entry points for project data management.
*
* @author Denis Zhdanov
* @since 4/16/13 11:38 AM
* @deprecated use {@link com.intellij.openapi.externalSystem.service.project.ProjectDataManager} instead
*/
public class ProjectDataManager {
private static final Logger LOG = Logger.getInstance("#" + ProjectDataManager.class.getName());
private static final com.intellij.openapi.util.Key<Boolean> DATA_READY =
com.intellij.openapi.util.Key.create("externalSystem.data.ready");
@NotNull private final NotNullLazyValue<Map<Key<?>, List<ProjectDataService<?, ?>>>> myServices;
public class ProjectDataManager extends ProjectDataManagerImpl {
public static ProjectDataManager getInstance() {
return ServiceManager.getService(ProjectDataManager.class);
return new ProjectDataManager(ProjectDataManagerImpl.getInstance());
}
public ProjectDataManager() {
myServices = new NotNullLazyValue<Map<Key<?>, List<ProjectDataService<?, ?>>>>() {
@NotNull
@Override
protected Map<Key<?>, List<ProjectDataService<?, ?>>> compute() {
Map<Key<?>, List<ProjectDataService<?, ?>>> result = ContainerUtilRt.newHashMap();
for (ProjectDataService<?, ?> service : ProjectDataService.EP_NAME.getExtensions()) {
List<ProjectDataService<?, ?>> services = result.get(service.getTargetDataKey());
if (services == null) {
result.put(service.getTargetDataKey(), services = ContainerUtilRt.newArrayList());
}
services.add(service);
}
private final ProjectDataManagerImpl delegate;
for (List<ProjectDataService<?, ?>> services : result.values()) {
ExternalSystemApiUtil.orderAwareSort(services);
}
return result;
}
};
}
public ProjectDataManager(ProjectDataManagerImpl delegate) {this.delegate = delegate;}
@SuppressWarnings("unchecked")
@Override
public void importData(@NotNull Collection<DataNode<?>> nodes,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
if (project.isDisposed()) return;
MultiMap<Key<?>, DataNode<?>> grouped = ExternalSystemApiUtil.recursiveGroup(nodes);
for (Key<?> key : myServices.getValue().keySet()) {
if (!grouped.containsKey(key)) {
grouped.put(key, Collections.<DataNode<?>>emptyList());
}
}
final Collection<DataNode<?>> projects = grouped.get(ProjectKeys.PROJECT);
// only one project(can be multi-module project) expected for per single import
assert projects.size() == 1 || projects.isEmpty();
final DataNode<ProjectData> projectNode = (DataNode<ProjectData>)ContainerUtil.getFirstItem(projects);
final ProjectData projectData;
ProjectSystemId projectSystemId;
if (projectNode != null) {
projectData = projectNode.getData();
projectSystemId = projectNode.getData().getOwner();
ExternalProjectsDataStorage.getInstance(project).saveInclusionSettings(projectNode);
}
else {
projectData = null;
DataNode<ModuleData> aModuleNode = (DataNode<ModuleData>)ContainerUtil.getFirstItem(grouped.get(ProjectKeys.MODULE));
projectSystemId = aModuleNode != null ? aModuleNode.getData().getOwner() : null;
}
if (projectSystemId != null) {
ExternalSystemUtil.scheduleExternalViewStructureUpdate(project, projectSystemId);
}
List<Runnable> onSuccessImportTasks = ContainerUtil.newSmartList();
try {
final Set<Map.Entry<Key<?>, Collection<DataNode<?>>>> entries = grouped.entrySet();
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
indicator.setIndeterminate(false);
}
final int size = entries.size();
int count = 0;
List<Runnable> postImportTasks = ContainerUtil.newSmartList();
for (Map.Entry<Key<?>, Collection<DataNode<?>>> entry : entries) {
if (indicator != null) {
String message = ExternalSystemBundle.message(
"progress.update.text", projectSystemId != null ? projectSystemId.getReadableName() : "",
"Refresh " + getReadableText(entry.getKey()));
indicator.setText(message);
indicator.setFraction((double)count++ / size);
}
doImportData(entry.getKey(), entry.getValue(), projectData, project, modelsProvider, postImportTasks, onSuccessImportTasks);
}
for (Runnable postImportTask : postImportTasks) {
postImportTask.run();
}
commit(modelsProvider, project, synchronous, "Imported data");
if (indicator != null) {
indicator.setIndeterminate(true);
}
}
catch (Throwable t) {
dispose(modelsProvider, project, synchronous);
ExceptionUtil.rethrowAllAsUnchecked(t);
}
for (Runnable onSuccessImportTask : ContainerUtil.reverse(onSuccessImportTasks)) {
onSuccessImportTask.run();
}
delegate.importData(nodes, project, modelsProvider, synchronous);
}
@NotNull
private static String getReadableText(@NotNull Key key) {
StringBuilder buffer = new StringBuilder();
String s = key.toString();
for (int i = 0; i < s.length(); i++) {
char currChar = s.charAt(i);
if (Character.isUpperCase(currChar)) {
if (i != 0) {
buffer.append(' ');
}
buffer.append(StringUtil.toLowerCase(currChar));
}
else {
buffer.append(currChar);
}
}
return buffer.toString();
}
public <T> void importData(@NotNull Collection<DataNode<T>> nodes, @NotNull Project project, boolean synchronous) {
Collection<DataNode<?>> dummy = ContainerUtil.newSmartList();
for (DataNode<T> node : nodes) {
dummy.add(node);
}
importData(dummy, project, new IdeModifiableModelsProviderImpl(project), synchronous);
@Override
public <T> void importData(@NotNull Collection<DataNode<T>> nodes,
@NotNull Project project, boolean synchronous) {
delegate.importData(nodes, project, synchronous);
}
@Override
public <T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
Collection<DataNode<?>> dummy = ContainerUtil.newSmartList();
dummy.add(node);
importData(dummy, project, modelsProvider, synchronous);
delegate.importData(node, project, modelsProvider, synchronous);
}
@Override
public <T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
boolean synchronous) {
importData(node, project, new IdeModifiableModelsProviderImpl(project), synchronous);
}
@SuppressWarnings("unchecked")
private <T> void doImportData(@NotNull Key<T> key,
@NotNull Collection<DataNode<?>> nodes,
@Nullable final ProjectData projectData,
@NotNull final Project project,
@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull final List<Runnable> postImportTasks,
@NotNull final List<Runnable> onSuccessImportTasks) {
if (project.isDisposed()) return;
if (project instanceof ProjectImpl) {
assert ((ProjectImpl)project).isComponentsCreated();
}
final List<DataNode<T>> toImport = ContainerUtil.newSmartList();
final List<DataNode<T>> toIgnore = ContainerUtil.newSmartList();
for (DataNode node : nodes) {
if (!key.equals(node.getKey())) continue;
if (node.isIgnored()) {
toIgnore.add(node);
}
else {
toImport.add(node);
}
}
ensureTheDataIsReadyToUse((Collection)toImport);
final List<ProjectDataService<?, ?>> services = myServices.getValue().get(key);
if (services == null) {
LOG.warn(String.format(
"Can't import data nodes '%s'. Reason: no service is registered for key %s. Available services for %s",
toImport, key, myServices.getValue().keySet()
));
}
else {
for (ProjectDataService<?, ?> service : services) {
final long importStartTime = System.currentTimeMillis();
((ProjectDataService)service).importData(toImport, projectData, project, modelsProvider);
if(LOG.isDebugEnabled()) {
final long importTimeInMs = (System.currentTimeMillis() - importStartTime);
LOG.debug(String.format("Service %s imported data in %d ms", service.getClass().getSimpleName(), importTimeInMs));
}
if(projectData != null) {
ensureTheDataIsReadyToUse((Collection)toIgnore);
final long removeStartTime = System.currentTimeMillis();
final Computable<Collection<?>> orphanIdeDataComputable =
((ProjectDataService)service).computeOrphanData(toImport, projectData, project, modelsProvider);
((ProjectDataService)service).removeData(orphanIdeDataComputable, toIgnore, projectData, project, modelsProvider);
if(LOG.isDebugEnabled()) {
final long removeTimeInMs = (System.currentTimeMillis() - removeStartTime);
LOG.debug(String.format("Service %s computed and removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs));
}
}
}
}
if (services != null && projectData != null) {
postImportTasks.add(() -> {
for (ProjectDataService<?, ?> service : services) {
if (service instanceof AbstractProjectDataService) {
final long taskStartTime = System.currentTimeMillis();
((AbstractProjectDataService)service).postProcess(toImport, projectData, project, modelsProvider);
if(LOG.isDebugEnabled()) {
final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime);
LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs));
}
}
}
});
onSuccessImportTasks.add(() -> {
for (ProjectDataService<?, ?> service : services) {
if (service instanceof AbstractProjectDataService) {
final long taskStartTime = System.currentTimeMillis();
((AbstractProjectDataService)service).onSuccessImport(project);
if(LOG.isDebugEnabled()) {
final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime);
LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs));
}
}
}
});
}
@NotNull Project project, boolean synchronous) {
delegate.importData(node, project, synchronous);
}
@Override
public void ensureTheDataIsReadyToUse(@Nullable DataNode dataNode) {
if (dataNode == null) return;
if (Boolean.TRUE.equals(dataNode.getUserData(DATA_READY))) return;
ExternalSystemApiUtil.visit(dataNode, dataNode1 -> {
prepareDataToUse(dataNode1);
dataNode1.putUserData(DATA_READY, Boolean.TRUE);
});
delegate.ensureTheDataIsReadyToUse(dataNode);
}
@SuppressWarnings("unchecked")
@Override
public <E, I> void removeData(@NotNull Key<E> key,
@NotNull Collection<I> toRemove,
@NotNull final Collection<DataNode<E>> toIgnore,
@NotNull final ProjectData projectData,
@NotNull Collection<DataNode<E>> toIgnore,
@NotNull ProjectData projectData,
@NotNull Project project,
@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
try {
List<ProjectDataService<?, ?>> services = myServices.getValue().get(key);
for (ProjectDataService service : services) {
final long removeStartTime = System.currentTimeMillis();
service.removeData(new Computable.PredefinedValueComputable<Collection>(toRemove), toIgnore, projectData, project, modelsProvider);
if(LOG.isDebugEnabled()) {
final long removeTimeInMs = System.currentTimeMillis() - removeStartTime;
LOG.debug(String.format("Service %s removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs));
}
}
commit(modelsProvider, project, synchronous, "Removed data");
}
catch (Throwable t) {
dispose(modelsProvider, project, synchronous);
ExceptionUtil.rethrowAllAsUnchecked(t);
}
delegate.removeData(key, toRemove, toIgnore, projectData, project, modelsProvider, synchronous);
}
@Override
public <E, I> void removeData(@NotNull Key<E> key,
@NotNull Collection<I> toRemove,
@NotNull final Collection<DataNode<E>> toIgnore,
@NotNull final ProjectData projectData,
@NotNull Project project,
boolean synchronous) {
removeData(key, toRemove, toIgnore, projectData, project, new IdeModifiableModelsProviderImpl(project), synchronous);
@NotNull Collection<DataNode<E>> toIgnore,
@NotNull ProjectData projectData,
@NotNull Project project, boolean synchronous) {
delegate.removeData(key, toRemove, toIgnore, projectData, project, synchronous);
}
public void updateExternalProjectData(@NotNull Project project, @NotNull ExternalProjectInfo externalProjectInfo) {
if (!project.isDisposed()) {
ExternalProjectsManager.getInstance(project).updateExternalProjectData(externalProjectInfo);
}
@Override
public void updateExternalProjectData(@NotNull Project project,
@NotNull ExternalProjectInfo externalProjectInfo) {
delegate.updateExternalProjectData(project, externalProjectInfo);
}
@Nullable
@Override
public ExternalProjectInfo getExternalProjectData(@NotNull Project project,
@NotNull ProjectSystemId projectSystemId,
@NotNull String externalProjectPath) {
return !project.isDisposed() ? ExternalProjectsDataStorage.getInstance(project).get(projectSystemId, externalProjectPath) : null;
return delegate.getExternalProjectData(project, projectSystemId, externalProjectPath);
}
@NotNull
public Collection<ExternalProjectInfo> getExternalProjectsData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId) {
if (!project.isDisposed()) {
return ExternalProjectsDataStorage.getInstance(project).list(projectSystemId);
}
else {
return ContainerUtil.emptyList();
}
}
private void ensureTheDataIsReadyToUse(@NotNull Collection<DataNode<?>> nodes) {
for (DataNode<?> node : nodes) {
ensureTheDataIsReadyToUse(node);
}
}
private void prepareDataToUse(@NotNull DataNode dataNode) {
final Map<Key<?>, List<ProjectDataService<?, ?>>> servicesByKey = myServices.getValue();
List<ProjectDataService<?, ?>> services = servicesByKey.get(dataNode.getKey());
if (services != null) {
try {
dataNode.prepareData(map2Array(services, ClassLoader.class, service -> service.getClass().getClassLoader()));
}
catch (Exception e) {
LOG.debug(e);
dataNode.clear(true);
}
}
}
private static void commit(@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull Project project,
boolean synchronous,
@NotNull final String commitDesc) {
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
@Override
public void execute() {
final long startTime = System.currentTimeMillis();
modelsProvider.commit();
final long timeInMs = System.currentTimeMillis() - startTime;
LOG.debug(String.format("%s committed in %d ms", commitDesc, timeInMs));
}
});
}
private static void dispose(@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull Project project,
boolean synchronous) {
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
@Override
public void execute() {
modelsProvider.dispose();
}
});
@Override
public Collection<ExternalProjectInfo> getExternalProjectsData(@NotNull Project project,
@NotNull ProjectSystemId projectSystemId) {
return delegate.getExternalProjectsData(project, projectSystemId);
}
}
@@ -0,0 +1,416 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.externalSystem.service.project.manage;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.*;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.util.containers.ContainerUtil.map2Array;
/**
* Aggregates all {@link ProjectDataService#EP_NAME registered data services} and provides entry points for project data management.
*
* @author Denis Zhdanov
* @since 4/16/13 11:38 AM
*/
public class ProjectDataManagerImpl implements ProjectDataManager {
private static final Logger LOG = Logger.getInstance("#" + ProjectDataManagerImpl.class.getName());
private static final com.intellij.openapi.util.Key<Boolean> DATA_READY =
com.intellij.openapi.util.Key.create("externalSystem.data.ready");
@NotNull private final NotNullLazyValue<Map<Key<?>, List<ProjectDataService<?, ?>>>> myServices;
public static ProjectDataManagerImpl getInstance() {
ProjectDataManager service = ServiceManager.getService(ProjectDataManager.class);
return (ProjectDataManagerImpl)service;
}
public ProjectDataManagerImpl() {
myServices = new NotNullLazyValue<Map<Key<?>, List<ProjectDataService<?, ?>>>>() {
@NotNull
@Override
protected Map<Key<?>, List<ProjectDataService<?, ?>>> compute() {
Map<Key<?>, List<ProjectDataService<?, ?>>> result = ContainerUtilRt.newHashMap();
for (ProjectDataService<?, ?> service : ProjectDataService.EP_NAME.getExtensions()) {
List<ProjectDataService<?, ?>> services = result.get(service.getTargetDataKey());
if (services == null) {
result.put(service.getTargetDataKey(), services = ContainerUtilRt.newArrayList());
}
services.add(service);
}
for (List<ProjectDataService<?, ?>> services : result.values()) {
ExternalSystemApiUtil.orderAwareSort(services);
}
return result;
}
};
}
@SuppressWarnings("unchecked")
@Override
public void importData(@NotNull Collection<DataNode<?>> nodes,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
if (project.isDisposed()) return;
MultiMap<Key<?>, DataNode<?>> grouped = ExternalSystemApiUtil.recursiveGroup(nodes);
for (Key<?> key : myServices.getValue().keySet()) {
if (!grouped.containsKey(key)) {
grouped.put(key, Collections.emptyList());
}
}
final Collection<DataNode<?>> projects = grouped.get(ProjectKeys.PROJECT);
// only one project(can be multi-module project) expected for per single import
assert projects.size() == 1 || projects.isEmpty();
final DataNode<ProjectData> projectNode = (DataNode<ProjectData>)ContainerUtil.getFirstItem(projects);
final ProjectData projectData;
ProjectSystemId projectSystemId;
if (projectNode != null) {
projectData = projectNode.getData();
projectSystemId = projectNode.getData().getOwner();
ExternalProjectsDataStorage.getInstance(project).saveInclusionSettings(projectNode);
}
else {
projectData = null;
DataNode<ModuleData> aModuleNode = (DataNode<ModuleData>)ContainerUtil.getFirstItem(grouped.get(ProjectKeys.MODULE));
projectSystemId = aModuleNode != null ? aModuleNode.getData().getOwner() : null;
}
if (projectSystemId != null) {
ExternalSystemUtil.scheduleExternalViewStructureUpdate(project, projectSystemId);
}
List<Runnable> onSuccessImportTasks = ContainerUtil.newSmartList();
try {
final Set<Map.Entry<Key<?>, Collection<DataNode<?>>>> entries = grouped.entrySet();
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
indicator.setIndeterminate(false);
}
final int size = entries.size();
int count = 0;
List<Runnable> postImportTasks = ContainerUtil.newSmartList();
for (Map.Entry<Key<?>, Collection<DataNode<?>>> entry : entries) {
if (indicator != null) {
String message = ExternalSystemBundle.message(
"progress.update.text", projectSystemId != null ? projectSystemId.getReadableName() : "",
"Refresh " + getReadableText(entry.getKey()));
indicator.setText(message);
indicator.setFraction((double)count++ / size);
}
doImportData(entry.getKey(), entry.getValue(), projectData, project, modelsProvider, postImportTasks, onSuccessImportTasks);
}
for (Runnable postImportTask : postImportTasks) {
postImportTask.run();
}
commit(modelsProvider, project, synchronous, "Imported data");
if (indicator != null) {
indicator.setIndeterminate(true);
}
project.getMessageBus().syncPublisher(ProjectDataImportListener.TOPIC)
.onImportFinished(projectData != null ? projectData.getLinkedExternalProjectPath() : null);
}
catch (Throwable t) {
dispose(modelsProvider, project, synchronous);
ExceptionUtil.rethrowAllAsUnchecked(t);
}
for (Runnable onSuccessImportTask : ContainerUtil.reverse(onSuccessImportTasks)) {
onSuccessImportTask.run();
}
}
@NotNull
private static String getReadableText(@NotNull Key key) {
StringBuilder buffer = new StringBuilder();
String s = key.toString();
for (int i = 0; i < s.length(); i++) {
char currChar = s.charAt(i);
if (Character.isUpperCase(currChar)) {
if (i != 0) {
buffer.append(' ');
}
buffer.append(StringUtil.toLowerCase(currChar));
}
else {
buffer.append(currChar);
}
}
return buffer.toString();
}
@Override
public <T> void importData(@NotNull Collection<DataNode<T>> nodes, @NotNull Project project, boolean synchronous) {
Collection<DataNode<?>> dummy = ContainerUtil.newSmartList();
dummy.addAll(nodes);
importData(dummy, project, new IdeModifiableModelsProviderImpl(project), synchronous);
}
@Override
public <T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
Collection<DataNode<?>> dummy = ContainerUtil.newSmartList();
dummy.add(node);
importData(dummy, project, modelsProvider, synchronous);
}
@Override
public <T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
boolean synchronous) {
importData(node, project, new IdeModifiableModelsProviderImpl(project), synchronous);
}
@SuppressWarnings("unchecked")
private <T> void doImportData(@NotNull Key<T> key,
@NotNull Collection<DataNode<?>> nodes,
@Nullable final ProjectData projectData,
@NotNull final Project project,
@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull final List<Runnable> postImportTasks,
@NotNull final List<Runnable> onSuccessImportTasks) {
if (project.isDisposed()) return;
if (project instanceof ProjectImpl) {
assert ((ProjectImpl)project).isComponentsCreated();
}
final List<DataNode<T>> toImport = ContainerUtil.newSmartList();
final List<DataNode<T>> toIgnore = ContainerUtil.newSmartList();
for (DataNode node : nodes) {
if (!key.equals(node.getKey())) continue;
if (node.isIgnored()) {
toIgnore.add(node);
}
else {
toImport.add(node);
}
}
ensureTheDataIsReadyToUse((Collection)toImport);
final List<ProjectDataService<?, ?>> services = myServices.getValue().get(key);
if (services == null) {
LOG.warn(String.format(
"Can't import data nodes '%s'. Reason: no service is registered for key %s. Available services for %s",
toImport, key, myServices.getValue().keySet()
));
}
else {
for (ProjectDataService<?, ?> service : services) {
final long importStartTime = System.currentTimeMillis();
((ProjectDataService)service).importData(toImport, projectData, project, modelsProvider);
if (LOG.isDebugEnabled()) {
final long importTimeInMs = (System.currentTimeMillis() - importStartTime);
LOG.debug(String.format("Service %s imported data in %d ms", service.getClass().getSimpleName(), importTimeInMs));
}
if (projectData != null) {
ensureTheDataIsReadyToUse((Collection)toIgnore);
final long removeStartTime = System.currentTimeMillis();
final Computable<Collection<?>> orphanIdeDataComputable =
((ProjectDataService)service).computeOrphanData(toImport, projectData, project, modelsProvider);
((ProjectDataService)service).removeData(orphanIdeDataComputable, toIgnore, projectData, project, modelsProvider);
if (LOG.isDebugEnabled()) {
final long removeTimeInMs = (System.currentTimeMillis() - removeStartTime);
LOG.debug(String.format("Service %s computed and removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs));
}
}
}
}
if (services != null && projectData != null) {
postImportTasks.add(() -> {
for (ProjectDataService<?, ?> service : services) {
if (service instanceof AbstractProjectDataService) {
final long taskStartTime = System.currentTimeMillis();
((AbstractProjectDataService)service).postProcess(toImport, projectData, project, modelsProvider);
if (LOG.isDebugEnabled()) {
final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime);
LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs));
}
}
}
});
onSuccessImportTasks.add(() -> {
for (ProjectDataService<?, ?> service : services) {
if (service instanceof AbstractProjectDataService) {
final long taskStartTime = System.currentTimeMillis();
((AbstractProjectDataService)service).onSuccessImport(project);
if (LOG.isDebugEnabled()) {
final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime);
LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs));
}
}
}
});
}
}
@Override
public void ensureTheDataIsReadyToUse(@Nullable DataNode dataNode) {
if (dataNode == null) return;
if (Boolean.TRUE.equals(dataNode.getUserData(DATA_READY))) return;
ExternalSystemApiUtil.visit(dataNode, dataNode1 -> {
prepareDataToUse(dataNode1);
dataNode1.putUserData(DATA_READY, Boolean.TRUE);
});
}
@SuppressWarnings("unchecked")
public <E, I> void removeData(@NotNull Key<E> key,
@NotNull Collection<I> toRemove,
@NotNull final Collection<DataNode<E>> toIgnore,
@NotNull final ProjectData projectData,
@NotNull Project project,
@NotNull final IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
try {
List<ProjectDataService<?, ?>> services = myServices.getValue().get(key);
for (ProjectDataService service : services) {
final long removeStartTime = System.currentTimeMillis();
service.removeData(new Computable.PredefinedValueComputable<Collection>(toRemove), toIgnore, projectData, project, modelsProvider);
if (LOG.isDebugEnabled()) {
final long removeTimeInMs = System.currentTimeMillis() - removeStartTime;
LOG.debug(String.format("Service %s removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs));
}
}
commit(modelsProvider, project, synchronous, "Removed data");
}
catch (Throwable t) {
dispose(modelsProvider, project, synchronous);
ExceptionUtil.rethrowAllAsUnchecked(t);
}
}
public <E, I> void removeData(@NotNull Key<E> key,
@NotNull Collection<I> toRemove,
@NotNull final Collection<DataNode<E>> toIgnore,
@NotNull final ProjectData projectData,
@NotNull Project project,
boolean synchronous) {
removeData(key, toRemove, toIgnore, projectData, project, new IdeModifiableModelsProviderImpl(project), synchronous);
}
public void updateExternalProjectData(@NotNull Project project, @NotNull ExternalProjectInfo externalProjectInfo) {
if (!project.isDisposed()) {
ExternalProjectsManagerImpl.getInstance(project).updateExternalProjectData(externalProjectInfo);
}
}
@Nullable
@Override
public ExternalProjectInfo getExternalProjectData(@NotNull Project project,
@NotNull ProjectSystemId projectSystemId,
@NotNull String externalProjectPath) {
return !project.isDisposed() ? ExternalProjectsDataStorage.getInstance(project).get(projectSystemId, externalProjectPath) : null;
}
@NotNull
@Override
public Collection<ExternalProjectInfo> getExternalProjectsData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId) {
if (!project.isDisposed()) {
return ExternalProjectsDataStorage.getInstance(project).list(projectSystemId);
}
else {
return ContainerUtil.emptyList();
}
}
private void ensureTheDataIsReadyToUse(@NotNull Collection<DataNode<?>> nodes) {
for (DataNode<?> node : nodes) {
ensureTheDataIsReadyToUse(node);
}
}
private void prepareDataToUse(@NotNull DataNode dataNode) {
final Map<Key<?>, List<ProjectDataService<?, ?>>> servicesByKey = myServices.getValue();
List<ProjectDataService<?, ?>> services = servicesByKey.get(dataNode.getKey());
if (services != null) {
try {
dataNode.prepareData(map2Array(services, ClassLoader.class, service -> service.getClass().getClassLoader()));
}
catch (Exception e) {
LOG.debug(e);
dataNode.clear(true);
}
}
}
private static void commit(@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull Project project,
boolean synchronous,
@NotNull final String commitDesc) {
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
@Override
public void execute() {
final long startTime = System.currentTimeMillis();
modelsProvider.commit();
final long timeInMs = System.currentTimeMillis() - startTime;
LOG.debug(String.format("%s committed in %d ms", commitDesc, timeInMs));
}
});
}
private static void dispose(@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull Project project,
boolean synchronous) {
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
@Override
public void execute() {
modelsProvider.dispose();
}
});
}
}
@@ -31,7 +31,8 @@ import com.intellij.openapi.externalSystem.model.project.Identifiable;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ModuleDependencyData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil;
@@ -123,7 +124,7 @@ public class ExternalProjectDataSelectorDialog extends DialogWrapper {
}
private void init(@NotNull ExternalProjectInfo projectInfo) {
ProjectDataManager.getInstance().ensureTheDataIsReadyToUse(projectInfo.getExternalProjectStructure());
ProjectDataManagerImpl.getInstance().ensureTheDataIsReadyToUse(projectInfo.getExternalProjectStructure());
myProjectInfo = projectInfo;
myExternalSystemUiAware = ExternalSystemUiUtil.getUiAware(myProjectInfo.getProjectSystemId());
myTree = createTree();
@@ -15,8 +15,6 @@
*/
package com.intellij.openapi.externalSystem.test;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.ex.CompilerPathsEx;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder;
@@ -26,7 +24,8 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode;
import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
@@ -45,14 +44,12 @@ import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.artifacts.ArtifactManager;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.util.BooleanFunction;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ContainerUtil;
@@ -162,7 +159,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
List<String> actual = new ArrayList<>();
for (ContentEntry contentRoot : contentRoots) {
for (SourceFolder f : contentRoot.getSourceFolders(rootType)) {
rootUrl = rootUrl == null ? VirtualFileManager.extractPath(contentRoot.getUrl()) : VirtualFileManager.extractPath(rootUrl);
rootUrl = VirtualFileManager.extractPath(rootUrl == null ? contentRoot.getUrl() : rootUrl);
String folderUrl = VirtualFileManager.extractPath(f.getUrl());
if (folderUrl.startsWith(rootUrl)) {
int length = rootUrl.length() + 1;
@@ -215,7 +212,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
}
private static String getAbsolutePath(String path) {
path = VfsUtil.urlToPath(path);
path = VfsUtilCore.urlToPath(path);
path = PathUtil.getCanonicalPath(path);
return FileUtil.toSystemIndependentName(path);
}
@@ -364,28 +361,12 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
protected void assertArtifacts(String... expectedNames) {
final List<String> actualNames = ContainerUtil.map(
ArtifactManager.getInstance(myProject).getAllArtifactsIncludingInvalid(), new Function<Artifact, String>() {
@Override
public String fun(Artifact artifact) {
return artifact.getName();
}
});
ArtifactManager.getInstance(myProject).getAllArtifactsIncludingInvalid(),
(Function<Artifact, String>)artifact -> artifact.getName());
assertUnorderedElementsAreEqual(actualNames, expectedNames);
}
protected Module getModule(final String name) {
AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
try {
Module m = ModuleManager.getInstance(myProject).findModuleByName(name);
assertNotNull("Module " + name + " not found", m);
return m;
}
finally {
accessToken.finish();
}
}
private ContentEntry getContentRoot(String moduleName) {
ContentEntry[] ee = getContentRoots(moduleName);
List<String> roots = new ArrayList<>();
@@ -415,7 +396,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
}
protected void ignoreData(BooleanFunction<DataNode<?>> booleanFunction, final boolean ignored) {
final ExternalProjectInfo externalProjectInfo = ProjectDataManager.getInstance().getExternalProjectData(
final ExternalProjectInfo externalProjectInfo = ProjectDataManagerImpl.getInstance().getExternalProjectData(
myProject, getExternalSystemId(), getCurrentExternalProjectSettings().getExternalProjectPath());
assertNotNull(externalProjectInfo);