cleanup (inspection "Java | Class structure | Utility class is not 'final'")
[idea/community.git] / jps / model-serialization / src / org / jetbrains / jps / model / serialization / library / JpsSdkTableSerializer.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package org.jetbrains.jps.model.serialization.library;
3
4 import com.intellij.openapi.diagnostic.Logger;
5 import com.intellij.openapi.util.JDOMUtil;
6 import org.jdom.Element;
7 import org.jetbrains.annotations.NotNull;
8 import org.jetbrains.annotations.Nullable;
9 import org.jetbrains.jps.model.JpsDummyElement;
10 import org.jetbrains.jps.model.JpsElement;
11 import org.jetbrains.jps.model.JpsElementFactory;
12 import org.jetbrains.jps.model.java.JpsJavaExtensionService;
13 import org.jetbrains.jps.model.java.JpsJavaSdkType;
14 import org.jetbrains.jps.model.java.JpsJavaSdkTypeWrapper;
15 import org.jetbrains.jps.model.library.JpsLibrary;
16 import org.jetbrains.jps.model.library.JpsLibraryCollection;
17 import org.jetbrains.jps.model.library.JpsLibraryRoot;
18 import org.jetbrains.jps.model.library.JpsOrderRootType;
19 import org.jetbrains.jps.model.library.sdk.JpsSdk;
20 import org.jetbrains.jps.model.library.sdk.JpsSdkReference;
21 import org.jetbrains.jps.model.library.sdk.JpsSdkType;
22 import org.jetbrains.jps.model.module.JpsSdkReferencesTable;
23 import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension;
24
25 import java.io.File;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.List;
30
31 public final class JpsSdkTableSerializer {
32   private static final Logger LOG = Logger.getInstance(JpsSdkTableSerializer.class);
33
34   private static final JpsLibraryRootTypeSerializer[] PREDEFINED_ROOT_TYPE_SERIALIZERS = {
35     new JpsLibraryRootTypeSerializer("classPath", JpsOrderRootType.COMPILED, true),
36     new JpsLibraryRootTypeSerializer("sourcePath", JpsOrderRootType.SOURCES, true)
37   };
38   private static final JpsSdkPropertiesSerializer<JpsDummyElement> JPS_JAVA_SDK_PROPERTIES_LOADER =
39     new JpsSdkPropertiesSerializer<JpsDummyElement>("JavaSDK", JpsJavaSdkType.INSTANCE) {
40       @NotNull
41       @Override
42       public JpsDummyElement loadProperties(Element propertiesElement) {
43         return JpsElementFactory.getInstance().createDummyElement();
44       }
45
46       @Override
47       public void saveProperties(@NotNull JpsDummyElement properties, @NotNull Element element) {
48       }
49     };
50   private static final String JDK_TAG = "jdk";
51   private static final String NAME_TAG = "name";
52   private static final String TYPE_TAG = "type";
53   private static final String TYPE_ATTRIBUTE = "type";
54   private static final String ROOTS_TAG = "roots";
55   private static final String ROOT_TAG = "root";
56   private static final String VERSION_TAG = "version";
57   private static final String HOME_PATH_TAG = "homePath";
58   private static final String VALUE_ATTRIBUTE = "value";
59   private static final String COMPOSITE_TYPE = "composite";
60   private static final String SIMPLE_TYPE = "simple";
61   private static final String URL_ATTRIBUTE = "url";
62   private static final String ADDITIONAL_TAG = "additional";
63
64   public static void loadSdks(@Nullable Element sdkListElement, JpsLibraryCollection result) {
65     for (Element sdkElement : JDOMUtil.getChildren(sdkListElement, JDK_TAG)) {
66       result.addLibrary(loadSdk(sdkElement));
67     }
68   }
69
70   public static void saveSdks(JpsLibraryCollection libraryCollection, Element sdkListElement) {
71     for (JpsLibrary library : libraryCollection.getLibraries()) {
72       JpsElement properties = library.getProperties();
73       if (properties instanceof JpsSdk<?>) {
74         Element sdkTag = new Element(JDK_TAG);
75         saveSdk((JpsSdk<?>)properties, sdkTag);
76         sdkListElement.addContent(sdkTag);
77       }
78     }
79   }
80
81   private static JpsLibrary loadSdk(Element sdkElement) {
82     String name = getAttributeValue(sdkElement, NAME_TAG);
83     String typeId = getAttributeValue(sdkElement, TYPE_TAG);
84     LOG.debug("Loading " + typeId + " SDK '" + name + "'");
85     JpsSdkPropertiesSerializer<?> serializer = getSdkPropertiesSerializer(typeId);
86     final JpsLibrary library = createSdk(name, serializer, sdkElement);
87     final Element roots = sdkElement.getChild(ROOTS_TAG);
88     for (Element rootTypeElement : JDOMUtil.getChildren(roots)) {
89       JpsLibraryRootTypeSerializer rootTypeSerializer = getRootTypeSerializer(rootTypeElement.getName());
90       if (rootTypeSerializer != null) {
91         for (Element rootElement : rootTypeElement.getChildren()) {
92           loadRoots(rootElement, library, rootTypeSerializer.getType());
93         }
94       }
95       else {
96         LOG.info("root type serializer not found for " + rootTypeElement.getName());
97       }
98     }
99     if (LOG.isDebugEnabled()) {
100       List<File> files = library.getFiles(JpsOrderRootType.COMPILED);
101       LOG.debug(name + " SDK classpath (" + files.size() + " roots):");
102       for (File file : files) {
103         LOG.debug(" " + file.getAbsolutePath());
104       }
105     }
106     return library;
107   }
108
109   private static <P extends JpsElement> void saveSdk(final JpsSdk<P> sdk, Element sdkTag) {
110     JpsLibrary library = sdk.getParent();
111     sdkTag.setAttribute("version", "2");
112     setAttributeValue(sdkTag, NAME_TAG, library.getName());
113     JpsSdkPropertiesSerializer<P> serializer = getSdkPropertiesSerializer(sdk.getSdkType());
114     setAttributeValue(sdkTag, TYPE_TAG, serializer.getTypeId());
115     String versionString = sdk.getVersionString();
116     if (versionString != null) {
117       setAttributeValue(sdkTag, VERSION_TAG, versionString);
118     }
119     setAttributeValue(sdkTag, HOME_PATH_TAG, sdk.getHomePath());
120
121     Element rootsTag = new Element(ROOTS_TAG);
122     for (JpsLibraryRootTypeSerializer rootTypeSerializer : getRootTypeSerializers()) {
123       Element rootTypeTag = new Element(rootTypeSerializer.getTypeId());
124       Element compositeTag = new Element(ROOT_TAG);
125       compositeTag.setAttribute(TYPE_ATTRIBUTE, COMPOSITE_TYPE);
126       List<JpsLibraryRoot> roots = library.getRoots(rootTypeSerializer.getType());
127       for (JpsLibraryRoot root : roots) {
128         compositeTag.addContent(new Element(ROOT_TAG).setAttribute(TYPE_ATTRIBUTE, SIMPLE_TYPE).setAttribute(URL_ATTRIBUTE, root.getUrl()));
129       }
130       rootTypeTag.addContent(compositeTag);
131       rootsTag.addContent(rootTypeTag);
132     }
133     sdkTag.addContent(rootsTag);
134
135     Element additionalTag = new Element(ADDITIONAL_TAG);
136     serializer.saveProperties(sdk.getSdkProperties(), additionalTag);
137     sdkTag.addContent(additionalTag);
138   }
139
140   private static void setAttributeValue(Element tag, final String tagName, final String value) {
141     tag.addContent(new Element(tagName).setAttribute(VALUE_ATTRIBUTE, value));
142   }
143
144   private static void loadRoots(Element rootElement, JpsLibrary library, JpsOrderRootType rootType) {
145     final String type = rootElement.getAttributeValue(TYPE_ATTRIBUTE);
146     if (type.equals(COMPOSITE_TYPE)) {
147       for (Element element : rootElement.getChildren()) {
148         loadRoots(element, library, rootType);
149       }
150     }
151     else if (type.equals(SIMPLE_TYPE)) {
152       library.addRoot(rootElement.getAttributeValue(URL_ATTRIBUTE), rootType);
153     }
154   }
155
156   @Nullable
157   private static JpsLibraryRootTypeSerializer getRootTypeSerializer(String typeId) {
158     for (JpsLibraryRootTypeSerializer serializer : PREDEFINED_ROOT_TYPE_SERIALIZERS) {
159       if (serializer.getTypeId().equals(typeId)) {
160         return serializer;
161       }
162     }
163     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
164       for (JpsLibraryRootTypeSerializer serializer : extension.getSdkRootTypeSerializers()) {
165         if (serializer.getTypeId().equals(typeId)) {
166           return serializer;
167         }
168       }
169     }
170     return null;
171   }
172
173   private static List<JpsLibraryRootTypeSerializer> getRootTypeSerializers() {
174     List<JpsLibraryRootTypeSerializer> serializers = new ArrayList<>(Arrays.asList(PREDEFINED_ROOT_TYPE_SERIALIZERS));
175     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
176       serializers.addAll(extension.getSdkRootTypeSerializers());
177     }
178     Collections.sort(serializers);
179     return serializers;
180   }
181
182   private static <P extends JpsElement> JpsLibrary createSdk(String name, JpsSdkPropertiesSerializer<P> loader, Element sdkElement) {
183     String versionString = getAttributeValue(sdkElement, VERSION_TAG);
184     String homePath = getAttributeValue(sdkElement, HOME_PATH_TAG);
185     Element propertiesTag = sdkElement.getChild(ADDITIONAL_TAG);
186     P properties = loader.loadProperties(propertiesTag);
187     return JpsElementFactory.getInstance().createSdk(name, homePath, versionString, loader.getType(), properties);
188   }
189
190   public static JpsSdkPropertiesSerializer<?> getSdkPropertiesSerializer(@Nullable String typeId) {
191     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
192       for (JpsSdkPropertiesSerializer<?> loader : extension.getSdkPropertiesSerializers()) {
193         if (loader.getTypeId().equals(typeId)) {
194           return loader;
195         }
196       }
197     }
198     return JPS_JAVA_SDK_PROPERTIES_LOADER;
199   }
200
201   public static <P extends JpsElement> JpsSdkPropertiesSerializer<P> getSdkPropertiesSerializer(JpsSdkType<P> type) {
202     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
203       for (JpsSdkPropertiesSerializer<?> loader : extension.getSdkPropertiesSerializers()) {
204         if (loader.getType().equals(type)) {
205           //noinspection unchecked
206           return (JpsSdkPropertiesSerializer<P>)loader;
207         }
208       }
209     }
210     //noinspection unchecked
211     return (JpsSdkPropertiesSerializer<P>)JPS_JAVA_SDK_PROPERTIES_LOADER;
212   }
213
214   @Nullable
215   private static String getAttributeValue(Element element, String childName) {
216     final Element child = element.getChild(childName);
217     return child != null ? child.getAttributeValue(VALUE_ATTRIBUTE) : null;
218   }
219
220   public static JpsSdkType<?> getSdkType(@Nullable String typeId) {
221     return getSdkPropertiesSerializer(typeId).getType();
222   }
223
224   public static JpsSdkPropertiesSerializer<?> getLoader(JpsSdkType<?> type) {
225     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
226       for (JpsSdkPropertiesSerializer<?> loader : extension.getSdkPropertiesSerializers()) {
227         if (loader.getType().equals(type)) {
228           return loader;
229         }
230       }
231     }
232     return JPS_JAVA_SDK_PROPERTIES_LOADER;
233   }
234
235   public static <P extends JpsElement> void setSdkReference(final JpsSdkReferencesTable table, String sdkName, JpsSdkType<P> sdkType) {
236     JpsSdkReference<P> reference = JpsElementFactory.getInstance().createSdkReference(sdkName, sdkType);
237     table.setSdkReference(sdkType, reference);
238     if (sdkType instanceof JpsJavaSdkTypeWrapper) {
239       JpsSdkReference<P> wrapperRef = JpsElementFactory.getInstance().createSdkReference(sdkName, sdkType);
240       table.setSdkReference(JpsJavaSdkType.INSTANCE, JpsJavaExtensionService.getInstance().createWrappedJavaSdkReference((JpsJavaSdkTypeWrapper)sdkType,
241                                                                                                                          wrapperRef));
242     }
243   }
244 }