86c0ffad429f42a220eda8f72555f2557b3bf863
[idea/community.git] / platform / external-system-api / src / com / intellij / openapi / externalSystem / model / project / ContentRootData.java
1 package com.intellij.openapi.externalSystem.model.project;
2
3 import com.intellij.openapi.externalSystem.model.ProjectSystemId;
4 import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
5 import com.intellij.openapi.util.io.FileUtil;
6 import com.intellij.openapi.util.text.StringUtil;
7 import com.intellij.util.containers.ContainerUtilRt;
8 import org.jetbrains.annotations.NotNull;
9 import org.jetbrains.annotations.Nullable;
10
11 import java.io.File;
12 import java.io.Serializable;
13 import java.util.*;
14
15 /**
16  * @author Denis Zhdanov
17  * @since 8/9/11 6:25 PM
18  */
19 public class ContentRootData extends AbstractExternalEntityData {
20
21   private static final long serialVersionUID = 1L;
22
23   @NotNull private final Map<ExternalSystemSourceType, Collection<SourceRoot>> myData = ContainerUtilRt.newHashMap();
24
25   @NotNull private final String myRootPath;
26
27   /**
28    * Creates new <code>GradleContentRootImpl</code> object.
29    *
30    * @param rootPath  path to the root directory
31    */
32   public ContentRootData(@NotNull ProjectSystemId owner, @NotNull String rootPath) {
33     super(owner);
34     myRootPath = ExternalSystemApiUtil.toCanonicalPath(rootPath);
35   }
36
37   /**
38    * @param type      target dir type
39    * @return          directories of the target type configured for the current content root
40    */
41   @NotNull
42   public Collection<SourceRoot> getPaths(@NotNull ExternalSystemSourceType type) {
43     final Collection<SourceRoot> result = myData.get(type);
44     return result == null ? Collections.emptyList() : result;
45   }
46
47   public void storePath(@NotNull ExternalSystemSourceType type, @NotNull String path) throws IllegalArgumentException {
48     storePath(type, path, null);
49   }
50
51   /**
52    * Ask to remember that directory at the given path contains sources of the given type.
53    *
54    * @param type           target sources type
55    * @param path           target source directory path
56    * @param packagePrefix  target source directory package prefix
57    * @throws IllegalArgumentException   if given path points to the directory that is not located
58    *                                    under the {@link #getRootPath() content root}
59    */
60   public void storePath(@NotNull ExternalSystemSourceType type, @NotNull String path, @Nullable String packagePrefix) throws IllegalArgumentException {
61     if (FileUtil.isAncestor(new File(getRootPath()), new File(path), false)) {
62       Collection<SourceRoot> paths = myData.get(type);
63       if (paths == null) {
64         myData.put(type, paths = new TreeSet<>(SourceRootComparator.INSTANCE));
65       }
66       paths.add(new SourceRoot(
67         ExternalSystemApiUtil.toCanonicalPath(path),
68         StringUtil.nullize(packagePrefix, true)
69       ));
70       return;
71     }
72     if (!ExternalSystemSourceType.EXCLUDED.equals(type)) { // There are external systems which mark output directory as 'excluded' path.
73       // We don't need to bother if it's outside a module content root then.
74       throw new IllegalArgumentException(String.format(
75         "Can't register given path of type '%s' because it's out of content root.%nContent root: '%s'%nGiven path: '%s'",
76         type, getRootPath(), new File(path).getAbsolutePath()
77       ));
78     }
79   }
80
81   @NotNull
82   public String getRootPath() {
83     return myRootPath;
84   }
85
86   @Override
87   public String toString() {
88     StringBuilder buffer = new StringBuilder("content root:");
89     for (Map.Entry<ExternalSystemSourceType, Collection<SourceRoot>> entry : myData.entrySet()) {
90       buffer.append(entry.getKey().toString().toLowerCase(Locale.ENGLISH)).append("=").append(entry.getValue()).append("|");
91     }
92     if (!myData.isEmpty()) {
93       buffer.setLength(buffer.length() - 1);
94     }
95     return buffer.toString();
96   }
97
98   public static class SourceRoot implements Serializable {
99     @NotNull
100     private final String myPath;
101
102     @Nullable
103     private final String myPackagePrefix;
104
105     public SourceRoot(@NotNull String path, @Nullable String prefix) {
106       myPath = path;
107       myPackagePrefix = prefix;
108     }
109
110     @NotNull
111     public String getPath() {
112       return myPath;
113     }
114
115     @Nullable
116     public String getPackagePrefix() {
117       return myPackagePrefix;
118     }
119
120     @Override
121     public boolean equals(Object o) {
122       if (this == o) return true;
123       if (!(o instanceof SourceRoot)) return false;
124       SourceRoot root = (SourceRoot)o;
125       if (myPackagePrefix != null ? !myPackagePrefix.equals(root.myPackagePrefix) : root.myPackagePrefix != null) return false;
126       if (!myPath.equals(root.myPath)) return false;
127       return true;
128     }
129
130     @Override
131     public int hashCode() {
132       int result = myPath.hashCode();
133       result = 31 * result + (myPackagePrefix != null ? myPackagePrefix.hashCode() : 0);
134       return result;
135     }
136
137     @Override
138     public String toString() {
139       StringBuilder buffer = new StringBuilder("source_root(");
140       buffer.append(myPath);
141       if (myPackagePrefix != null) {
142         buffer.append(", ").append(myPackagePrefix);
143       }
144       buffer.append(")");
145       return buffer.toString();
146     }
147   }
148
149   private static final class SourceRootComparator implements Comparator<SourceRoot>, Serializable {
150     private static final SourceRootComparator INSTANCE = new SourceRootComparator();
151
152     @Override
153     public int compare(@NotNull SourceRoot o1, @NotNull SourceRoot o2) {
154       return StringUtil.naturalCompare(o1.myPath, o2.myPath);
155     }
156   }
157 }