summaryrefslogtreecommitdiff
path: root/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java
blob: 6575ffb107f0921f872227ef9f74ea901c837a9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 * 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.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.Key;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 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 ProjectDataManager {

  private static final Logger LOG = Logger.getInstance("#" + ProjectDataManager.class.getName());

  @NotNull private final NotNullLazyValue<Map<Key<?>, List<ProjectDataService<?, ?>>>> 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")
  public <T> void importData(@NotNull Collection<DataNode<?>> nodes, @NotNull Project project, boolean synchronous) {
    Map<Key<?>, List<DataNode<?>>> grouped = ExternalSystemApiUtil.group(nodes);
    for (Map.Entry<Key<?>, List<DataNode<?>>> entry : grouped.entrySet()) {
      // Simple class cast makes ide happy but compiler fails.
      Collection<DataNode<T>> dummy = ContainerUtilRt.newArrayList();
      for (DataNode<?> node : entry.getValue()) {
        dummy.add((DataNode<T>)node);
      }
      importData((Key<T>)entry.getKey(), dummy, project, synchronous);
    }
  }

  @SuppressWarnings("unchecked")
  public <T> void importData(@NotNull Key<T> key, @NotNull Collection<DataNode<T>> nodes, @NotNull Project project, boolean synchronous) {
    ensureTheDataIsReadyToUse(nodes);
    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",
        nodes, key, myServices.getValue().keySet()
      ));
    }
    else {
      for (ProjectDataService<?, ?> service : services) {
        ((ProjectDataService<T, ?>)service).importData(nodes, project, synchronous);
      }
    }

    Collection<DataNode<?>> children = ContainerUtilRt.newArrayList();
    for (DataNode<T> node : nodes) {
      children.addAll(node.getChildren());
    }
    importData(children, project, synchronous);
  }

  @SuppressWarnings("unchecked")
  private <T> void ensureTheDataIsReadyToUse(@NotNull Collection<DataNode<T>> nodes) {
    Map<Key<?>, List<ProjectDataService<?, ?>>> servicesByKey = myServices.getValue();
    Stack<DataNode<T>> toProcess = ContainerUtil.newStack(nodes);
    while (!toProcess.isEmpty()) {
      DataNode<T> node = toProcess.pop();
      List<ProjectDataService<?, ?>> services = servicesByKey.get(node.getKey());
      if (services != null) {
        for (ProjectDataService<?, ?> service : services) {
          node.prepareData(service.getClass().getClassLoader());
        }
      }

      for (DataNode<?> dataNode : node.getChildren()) {
        toProcess.push((DataNode<T>)dataNode);
      }
    }
  }

  @SuppressWarnings("unchecked")
  public <T> void removeData(@NotNull Key<?> key, @NotNull Collection<T> toRemove, @NotNull Project project, boolean synchronous) {
    List<ProjectDataService<?, ?>> services = myServices.getValue().get(key);
    for (ProjectDataService<?, ?> service : services) {
      ((ProjectDataService<?, T>)service).removeData(toRemove, project, synchronous);
    }
  }
}