cleanup (inspection "Java | Class structure | Utility class is not 'final'")
[idea/community.git] / jps / model-serialization / src / org / jetbrains / jps / model / serialization / artifact / JpsArtifactSerializer.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.artifact;
3
4 import com.intellij.openapi.util.JDOMUtil;
5 import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
6 import com.intellij.util.xmlb.XmlSerializer;
7 import org.jdom.Element;
8 import org.jetbrains.annotations.NotNull;
9 import org.jetbrains.annotations.Nullable;
10 import org.jetbrains.jps.model.*;
11 import org.jetbrains.jps.model.artifact.*;
12 import org.jetbrains.jps.model.artifact.elements.*;
13 import org.jetbrains.jps.model.library.JpsLibraryReference;
14 import org.jetbrains.jps.model.module.JpsModuleReference;
15 import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension;
16 import org.jetbrains.jps.model.serialization.library.JpsLibraryTableSerializer;
17
18 import java.util.List;
19
20 public final class JpsArtifactSerializer {
21   private static final JpsPackagingElementSerializer<?>[] STANDARD_SERIALIZERS = {
22     new ArtifactRootElementSerializer(),
23     new DirectoryElementSerializer(),
24     new ArchiveElementSerializer(),
25     new FileCopyElementSerializer(),
26     new DirectoryCopyElementSerializer(),
27     new ExtractedDirectoryElementSerializer(),
28     new LibraryFilesElementSerializer(),
29     new ArtifactOutputElementSerializer()
30   };
31   private static final JpsArtifactPropertiesSerializer<?>[] STANDARD_TYPE_SERIALIZERS = {
32     new JpsArtifactDummyPropertiesSerializer("plain", DirectoryArtifactType.INSTANCE),
33     new JpsArtifactDummyPropertiesSerializer("jar", JarArtifactType.INSTANCE)
34   };
35   private static final String ELEMENT_TAG = "element";
36   private static final String ID_ATTRIBUTE = "id";
37   private static final SkipDefaultValuesSerializationFilters SERIALIZATION_FILTERS = new SkipDefaultValuesSerializationFilters();
38
39
40   public static void loadArtifacts(@NotNull JpsProject project, @Nullable Element componentElement) {
41     JpsArtifactService service = JpsArtifactService.getInstance();
42     for (Element artifactElement : JDOMUtil.getChildren(componentElement, "artifact")) {
43       ArtifactState state = XmlSerializer.deserialize(artifactElement, ArtifactState.class);
44       JpsArtifactPropertiesSerializer<?> serializer = getTypePropertiesSerializer(state.getArtifactType());
45       loadArtifact(project, service, state, serializer);
46     }
47   }
48
49   private static <P extends JpsElement> void loadArtifact(JpsProject project, JpsArtifactService service, ArtifactState state, JpsArtifactPropertiesSerializer<P> serializer) {
50     JpsPackagingElement rootElement = loadPackagingElement(state.getRootElement());
51     if (rootElement != null) {
52       List<ArtifactPropertiesState> propertiesList = state.getPropertiesList();
53       JpsArtifact artifact = service.addArtifact(project, state.getName(), (JpsCompositePackagingElement)rootElement,
54                                                  serializer.getType(), serializer.loadProperties(propertiesList));
55       artifact.setBuildOnMake(state.isBuildOnMake());
56       artifact.setOutputPath(state.getOutputPath());
57       for (ArtifactPropertiesState propertiesState : propertiesList) {
58         JpsArtifactExtensionSerializer<?> extensionSerializer = getExtensionSerializer(propertiesState.getId());
59         if (extensionSerializer != null) {
60           loadExtension(extensionSerializer, artifact, propertiesState.getOptions());
61         }
62       }
63     }
64   }
65
66   public static void saveArtifact(@NotNull JpsArtifact artifact, Element componentElement) {
67     ArtifactState state = new ArtifactState();
68     state.setName(artifact.getName());
69     state.setBuildOnMake(artifact.isBuildOnMake());
70     state.setOutputPath(artifact.getOutputPath());
71     JpsArtifactPropertiesSerializer<?> serializer = getTypePropertiesSerializer(artifact.getArtifactType());
72     doSaveArtifact(artifact, componentElement, state, serializer);
73   }
74
75   private static <P extends JpsElement> void doSaveArtifact(JpsArtifact artifact, Element componentElement, ArtifactState state,
76                                                             JpsArtifactPropertiesSerializer<P> serializer) {
77     state.setArtifactType(serializer.getTypeId());
78     state.setRootElement(savePackagingElement(artifact.getRootElement()));
79     List<ArtifactPropertiesState> propertiesList = state.getPropertiesList();
80     //noinspection unchecked
81     serializer.saveProperties((P)artifact.getProperties(), propertiesList);
82     for (JpsModelSerializerExtension serializerExtension : JpsModelSerializerExtension.getExtensions()) {
83       for (JpsArtifactExtensionSerializer<?> extensionSerializer : serializerExtension.getArtifactExtensionSerializers()) {
84         JpsElement extension = artifact.getContainer().getChild(extensionSerializer.getRole());
85         if (extension != null) {
86           ArtifactPropertiesState propertiesState = new ArtifactPropertiesState();
87           propertiesState.setId(extensionSerializer.getId());
88           propertiesState.setOptions(saveExtension(extensionSerializer, extension));
89           propertiesList.add(propertiesState);
90         }
91       }
92     }
93     componentElement.addContent(XmlSerializer.serialize(state, SERIALIZATION_FILTERS));
94   }
95
96   private static <E extends JpsElement> void loadExtension(JpsArtifactExtensionSerializer<E> serializer,
97                                                            JpsArtifact artifact,
98                                                            Element options) {
99     E e = serializer.loadExtension(options);
100     artifact.getContainer().setChild(serializer.getRole(), e);
101   }
102
103   private static <E extends JpsElement> Element saveExtension(JpsArtifactExtensionSerializer<?> serializer,
104                                                               E extension) {
105     Element optionsTag = new Element("options");
106     //noinspection unchecked
107     ((JpsArtifactExtensionSerializer<E>)serializer).saveExtension(extension, optionsTag);
108     return optionsTag;
109   }
110
111   private static <P extends JpsPackagingElement> Element savePackagingElement(P element) {
112     //noinspection unchecked
113     JpsPackagingElementSerializer<P> serializer = findElementSerializer((Class<P>)element.getClass());
114     Element tag = new Element(ELEMENT_TAG).setAttribute(ID_ATTRIBUTE, serializer.getTypeId());
115     serializer.save(element, tag);
116     if (element instanceof JpsCompositePackagingElement) {
117       for (JpsPackagingElement child : ((JpsCompositePackagingElement)element).getChildren()) {
118         tag.addContent(savePackagingElement(child));
119       }
120     }
121     return tag;
122   }
123
124   @Nullable
125   private static JpsPackagingElement loadPackagingElement(Element element) {
126     JpsPackagingElement packagingElement = createPackagingElement(element);
127     if (packagingElement instanceof JpsCompositePackagingElement) {
128       for (Element childElement : JDOMUtil.getChildren(element, ELEMENT_TAG)) {
129         JpsPackagingElement child = loadPackagingElement(childElement);
130         if (child != null) {
131           ((JpsCompositePackagingElement)packagingElement).addChild(child);
132         }
133       }
134     }
135     return packagingElement;
136   }
137
138   @Nullable
139   private static JpsPackagingElement createPackagingElement(Element element) {
140     String typeId = element.getAttributeValue(ID_ATTRIBUTE);
141     JpsPackagingElementSerializer<?> serializer = findElementSerializer(typeId);
142     if (serializer != null) {
143       return serializer.load(element);
144     }
145     return null;
146   }
147
148   @Nullable
149   private static JpsPackagingElementSerializer<?> findElementSerializer(@NotNull String typeId) {
150     for (JpsPackagingElementSerializer<?> serializer : STANDARD_SERIALIZERS) {
151       if (serializer.getTypeId().equals(typeId)) {
152         return serializer;
153       }
154     }
155     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
156       for (JpsPackagingElementSerializer<?> serializer : extension.getPackagingElementSerializers()) {
157         if (serializer.getTypeId().equals(typeId)) {
158           return serializer;
159         }
160       }
161     }
162     return null;
163   }
164
165   @NotNull
166   private static <E extends JpsPackagingElement> JpsPackagingElementSerializer<E> findElementSerializer(@NotNull Class<E> elementClass) {
167     for (JpsPackagingElementSerializer<?> serializer : STANDARD_SERIALIZERS) {
168       if (serializer.getElementClass().isAssignableFrom(elementClass)) {
169         //noinspection unchecked
170         return (JpsPackagingElementSerializer<E>)serializer;
171       }
172     }
173     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
174       for (JpsPackagingElementSerializer<?> serializer : extension.getPackagingElementSerializers()) {
175         if (serializer.getElementClass().isAssignableFrom(elementClass)) {
176           //noinspection unchecked
177           return (JpsPackagingElementSerializer<E>)serializer;
178         }
179       }
180     }
181     throw new IllegalArgumentException("Serializer not found for " + elementClass);
182   }
183
184   @Nullable
185   private static JpsArtifactExtensionSerializer<?> getExtensionSerializer(String id) {
186     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
187       for (JpsArtifactExtensionSerializer<?> serializer : extension.getArtifactExtensionSerializers()) {
188         if (serializer.getId().equals(id)) {
189           return serializer;
190         }
191       }
192     }
193     return null;
194   }
195
196   private static JpsArtifactPropertiesSerializer<?> getTypePropertiesSerializer(String typeId) {
197     for (JpsArtifactPropertiesSerializer serializer : STANDARD_TYPE_SERIALIZERS) {
198       if (serializer.getTypeId().equals(typeId)) {
199         return serializer;
200       }
201     }
202     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
203       for (JpsArtifactPropertiesSerializer serializer : extension.getArtifactTypePropertiesSerializers()) {
204         if (serializer.getTypeId().equals(typeId)) {
205           return serializer;
206         }
207       }
208     }
209     return STANDARD_TYPE_SERIALIZERS[0];
210   }
211
212   private static JpsArtifactPropertiesSerializer<?> getTypePropertiesSerializer(JpsArtifactType type) {
213     for (JpsArtifactPropertiesSerializer serializer : STANDARD_TYPE_SERIALIZERS) {
214       if (serializer.getType().equals(type)) {
215         return serializer;
216       }
217     }
218     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
219       for (JpsArtifactPropertiesSerializer serializer : extension.getArtifactTypePropertiesSerializers()) {
220         if (serializer.getType().equals(type)) {
221           return serializer;
222         }
223       }
224     }
225     return null;
226   }
227
228   private static class ArtifactRootElementSerializer extends JpsPackagingElementSerializer<JpsArtifactRootElement> {
229     ArtifactRootElementSerializer() {
230       super("root", JpsArtifactRootElement.class);
231     }
232
233     @Override
234     public JpsArtifactRootElement load(Element element) {
235       return JpsPackagingElementFactory.getInstance().createArtifactRoot();
236     }
237
238     @Override
239     public void save(JpsArtifactRootElement element, Element tag) {
240     }
241   }
242
243   private static class DirectoryElementSerializer extends JpsPackagingElementSerializer<JpsDirectoryPackagingElement> {
244     DirectoryElementSerializer() {
245       super("directory", JpsDirectoryPackagingElement.class);
246     }
247
248     @Override
249     public JpsDirectoryPackagingElement load(Element element) {
250       return JpsPackagingElementFactory.getInstance().createDirectory(element.getAttributeValue("name"));
251     }
252
253     @Override
254     public void save(JpsDirectoryPackagingElement element, Element tag) {
255       tag.setAttribute("name", element.getDirectoryName());
256     }
257   }
258
259   private static class ArchiveElementSerializer extends JpsPackagingElementSerializer<JpsArchivePackagingElement> {
260     ArchiveElementSerializer() {
261       super("archive", JpsArchivePackagingElement.class);
262     }
263
264     @Override
265     public JpsArchivePackagingElement load(Element element) {
266       return JpsPackagingElementFactory.getInstance().createArchive(element.getAttributeValue("name"));
267     }
268
269     @Override
270     public void save(JpsArchivePackagingElement element, Element tag) {
271       tag.setAttribute("name", element.getArchiveName());
272     }
273   }
274
275   private static class FileCopyElementSerializer extends JpsPackagingElementSerializer<JpsFileCopyPackagingElement> {
276     FileCopyElementSerializer() {
277       super("file-copy", JpsFileCopyPackagingElement.class);
278     }
279
280     @Override
281     public JpsFileCopyPackagingElement load(Element element) {
282       return JpsPackagingElementFactory.getInstance().createFileCopy(element.getAttributeValue("path"),
283                                                                      element.getAttributeValue("output-file-name"));
284     }
285
286     @Override
287     public void save(JpsFileCopyPackagingElement element, Element tag) {
288       tag.setAttribute("path", element.getFilePath());
289       String outputFileName = element.getRenamedOutputFileName();
290       if (outputFileName != null) {
291         tag.setAttribute("output-path-name", outputFileName);
292       }
293     }
294   }
295
296   private static class DirectoryCopyElementSerializer extends JpsPackagingElementSerializer<JpsDirectoryCopyPackagingElement> {
297     DirectoryCopyElementSerializer() {
298       super("dir-copy", JpsDirectoryCopyPackagingElement.class);
299     }
300
301     @Override
302     public JpsDirectoryCopyPackagingElement load(Element element) {
303       return JpsPackagingElementFactory.getInstance().createDirectoryCopy(element.getAttributeValue("path"));
304     }
305
306     @Override
307     public void save(JpsDirectoryCopyPackagingElement element, Element tag) {
308       tag.setAttribute("path", element.getDirectoryPath());
309     }
310   }
311
312   private static class ExtractedDirectoryElementSerializer
313     extends JpsPackagingElementSerializer<JpsExtractedDirectoryPackagingElement> {
314     ExtractedDirectoryElementSerializer() {
315       super("extracted-dir", JpsExtractedDirectoryPackagingElement.class);
316     }
317
318     @Override
319     public JpsExtractedDirectoryPackagingElement load(Element element) {
320       return JpsPackagingElementFactory.getInstance().createExtractedDirectory(element.getAttributeValue("path"),
321                                                                                element.getAttributeValue("path-in-jar"));
322     }
323
324     @Override
325     public void save(JpsExtractedDirectoryPackagingElement element, Element tag) {
326       tag.setAttribute("path", element.getFilePath());
327       tag.setAttribute("path-in-jar", element.getPathInJar());
328     }
329   }
330
331   private static class LibraryFilesElementSerializer extends JpsPackagingElementSerializer<JpsLibraryFilesPackagingElement> {
332     LibraryFilesElementSerializer() {
333       super("library", JpsLibraryFilesPackagingElement.class);
334     }
335
336     @Override
337     public JpsLibraryFilesPackagingElement load(Element element) {
338       String level = element.getAttributeValue("level");
339       String libraryName = element.getAttributeValue("name");
340       String moduleName = element.getAttributeValue("module-name");
341       JpsElementReference<? extends JpsCompositeElement> parentReference;
342       if (moduleName != null) {
343         parentReference = JpsElementFactory.getInstance().createModuleReference(moduleName);
344       }
345       else {
346         parentReference = JpsLibraryTableSerializer.createLibraryTableReference(level);
347       }
348       return JpsPackagingElementFactory.getInstance()
349         .createLibraryElement(JpsElementFactory.getInstance().createLibraryReference(libraryName, parentReference));
350     }
351
352     @Override
353     public void save(JpsLibraryFilesPackagingElement element, Element tag) {
354       JpsLibraryReference reference = element.getLibraryReference();
355       JpsElementReference<? extends JpsCompositeElement> parentReference = reference.getParentReference();
356       tag.setAttribute("level", JpsLibraryTableSerializer.getLevelId(parentReference));
357       tag.setAttribute("name", reference.getLibraryName());
358       if (parentReference instanceof JpsModuleReference) {
359         tag.setAttribute("module-name", ((JpsModuleReference)parentReference).getModuleName());
360       }
361     }
362   }
363
364   private static class ArtifactOutputElementSerializer extends JpsPackagingElementSerializer<JpsArtifactOutputPackagingElement> {
365     ArtifactOutputElementSerializer() {
366       super("artifact", JpsArtifactOutputPackagingElement.class);
367     }
368
369     @Override
370     public JpsArtifactOutputPackagingElement load(Element element) {
371       return JpsPackagingElementFactory.getInstance()
372         .createArtifactOutput(JpsArtifactService.getInstance().createReference(element.getAttributeValue("artifact-name")));
373     }
374
375     @Override
376     public void save(JpsArtifactOutputPackagingElement element, Element tag) {
377       tag.setAttribute("artifact-name", element.getArtifactReference().getArtifactName());
378     }
379   }
380 }