use nio.Path instead of io.File in jps project serializers with check on file existence
[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     if (typeId == null) return null;
142     JpsPackagingElementSerializer<?> serializer = findElementSerializer(typeId);
143     if (serializer != null) {
144       return serializer.load(element);
145     }
146     return null;
147   }
148
149   @Nullable
150   private static JpsPackagingElementSerializer<?> findElementSerializer(@NotNull String typeId) {
151     for (JpsPackagingElementSerializer<?> serializer : STANDARD_SERIALIZERS) {
152       if (serializer.getTypeId().equals(typeId)) {
153         return serializer;
154       }
155     }
156     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
157       for (JpsPackagingElementSerializer<?> serializer : extension.getPackagingElementSerializers()) {
158         if (serializer.getTypeId().equals(typeId)) {
159           return serializer;
160         }
161       }
162     }
163     return null;
164   }
165
166   @NotNull
167   private static <E extends JpsPackagingElement> JpsPackagingElementSerializer<E> findElementSerializer(@NotNull Class<E> elementClass) {
168     for (JpsPackagingElementSerializer<?> serializer : STANDARD_SERIALIZERS) {
169       if (serializer.getElementClass().isAssignableFrom(elementClass)) {
170         //noinspection unchecked
171         return (JpsPackagingElementSerializer<E>)serializer;
172       }
173     }
174     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
175       for (JpsPackagingElementSerializer<?> serializer : extension.getPackagingElementSerializers()) {
176         if (serializer.getElementClass().isAssignableFrom(elementClass)) {
177           //noinspection unchecked
178           return (JpsPackagingElementSerializer<E>)serializer;
179         }
180       }
181     }
182     throw new IllegalArgumentException("Serializer not found for " + elementClass);
183   }
184
185   @Nullable
186   private static JpsArtifactExtensionSerializer<?> getExtensionSerializer(String id) {
187     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
188       for (JpsArtifactExtensionSerializer<?> serializer : extension.getArtifactExtensionSerializers()) {
189         if (serializer.getId().equals(id)) {
190           return serializer;
191         }
192       }
193     }
194     return null;
195   }
196
197   private static JpsArtifactPropertiesSerializer<?> getTypePropertiesSerializer(String typeId) {
198     for (JpsArtifactPropertiesSerializer serializer : STANDARD_TYPE_SERIALIZERS) {
199       if (serializer.getTypeId().equals(typeId)) {
200         return serializer;
201       }
202     }
203     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
204       for (JpsArtifactPropertiesSerializer serializer : extension.getArtifactTypePropertiesSerializers()) {
205         if (serializer.getTypeId().equals(typeId)) {
206           return serializer;
207         }
208       }
209     }
210     return STANDARD_TYPE_SERIALIZERS[0];
211   }
212
213   private static JpsArtifactPropertiesSerializer<?> getTypePropertiesSerializer(JpsArtifactType type) {
214     for (JpsArtifactPropertiesSerializer serializer : STANDARD_TYPE_SERIALIZERS) {
215       if (serializer.getType().equals(type)) {
216         return serializer;
217       }
218     }
219     for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
220       for (JpsArtifactPropertiesSerializer serializer : extension.getArtifactTypePropertiesSerializers()) {
221         if (serializer.getType().equals(type)) {
222           return serializer;
223         }
224       }
225     }
226     return null;
227   }
228
229   private static class ArtifactRootElementSerializer extends JpsPackagingElementSerializer<JpsArtifactRootElement> {
230     ArtifactRootElementSerializer() {
231       super("root", JpsArtifactRootElement.class);
232     }
233
234     @Override
235     public JpsArtifactRootElement load(Element element) {
236       return JpsPackagingElementFactory.getInstance().createArtifactRoot();
237     }
238
239     @Override
240     public void save(JpsArtifactRootElement element, Element tag) {
241     }
242   }
243
244   private static class DirectoryElementSerializer extends JpsPackagingElementSerializer<JpsDirectoryPackagingElement> {
245     DirectoryElementSerializer() {
246       super("directory", JpsDirectoryPackagingElement.class);
247     }
248
249     @Override
250     public JpsDirectoryPackagingElement load(Element element) {
251       return JpsPackagingElementFactory.getInstance().createDirectory(element.getAttributeValue("name"));
252     }
253
254     @Override
255     public void save(JpsDirectoryPackagingElement element, Element tag) {
256       tag.setAttribute("name", element.getDirectoryName());
257     }
258   }
259
260   private static class ArchiveElementSerializer extends JpsPackagingElementSerializer<JpsArchivePackagingElement> {
261     ArchiveElementSerializer() {
262       super("archive", JpsArchivePackagingElement.class);
263     }
264
265     @Override
266     public JpsArchivePackagingElement load(Element element) {
267       return JpsPackagingElementFactory.getInstance().createArchive(element.getAttributeValue("name"));
268     }
269
270     @Override
271     public void save(JpsArchivePackagingElement element, Element tag) {
272       tag.setAttribute("name", element.getArchiveName());
273     }
274   }
275
276   private static class FileCopyElementSerializer extends JpsPackagingElementSerializer<JpsFileCopyPackagingElement> {
277     FileCopyElementSerializer() {
278       super("file-copy", JpsFileCopyPackagingElement.class);
279     }
280
281     @Override
282     public JpsFileCopyPackagingElement load(Element element) {
283       return JpsPackagingElementFactory.getInstance().createFileCopy(element.getAttributeValue("path"),
284                                                                      element.getAttributeValue("output-file-name"));
285     }
286
287     @Override
288     public void save(JpsFileCopyPackagingElement element, Element tag) {
289       tag.setAttribute("path", element.getFilePath());
290       String outputFileName = element.getRenamedOutputFileName();
291       if (outputFileName != null) {
292         tag.setAttribute("output-path-name", outputFileName);
293       }
294     }
295   }
296
297   private static class DirectoryCopyElementSerializer extends JpsPackagingElementSerializer<JpsDirectoryCopyPackagingElement> {
298     DirectoryCopyElementSerializer() {
299       super("dir-copy", JpsDirectoryCopyPackagingElement.class);
300     }
301
302     @Override
303     public JpsDirectoryCopyPackagingElement load(Element element) {
304       return JpsPackagingElementFactory.getInstance().createDirectoryCopy(element.getAttributeValue("path"));
305     }
306
307     @Override
308     public void save(JpsDirectoryCopyPackagingElement element, Element tag) {
309       tag.setAttribute("path", element.getDirectoryPath());
310     }
311   }
312
313   private static class ExtractedDirectoryElementSerializer
314     extends JpsPackagingElementSerializer<JpsExtractedDirectoryPackagingElement> {
315     ExtractedDirectoryElementSerializer() {
316       super("extracted-dir", JpsExtractedDirectoryPackagingElement.class);
317     }
318
319     @Override
320     public JpsExtractedDirectoryPackagingElement load(Element element) {
321       return JpsPackagingElementFactory.getInstance().createExtractedDirectory(element.getAttributeValue("path"),
322                                                                                element.getAttributeValue("path-in-jar"));
323     }
324
325     @Override
326     public void save(JpsExtractedDirectoryPackagingElement element, Element tag) {
327       tag.setAttribute("path", element.getFilePath());
328       tag.setAttribute("path-in-jar", element.getPathInJar());
329     }
330   }
331
332   private static class LibraryFilesElementSerializer extends JpsPackagingElementSerializer<JpsLibraryFilesPackagingElement> {
333     LibraryFilesElementSerializer() {
334       super("library", JpsLibraryFilesPackagingElement.class);
335     }
336
337     @Override
338     public JpsLibraryFilesPackagingElement load(Element element) {
339       String level = element.getAttributeValue("level");
340       String libraryName = element.getAttributeValue("name");
341       String moduleName = element.getAttributeValue("module-name");
342       JpsElementReference<? extends JpsCompositeElement> parentReference;
343       if (moduleName != null) {
344         parentReference = JpsElementFactory.getInstance().createModuleReference(moduleName);
345       }
346       else {
347         parentReference = JpsLibraryTableSerializer.createLibraryTableReference(level);
348       }
349       return JpsPackagingElementFactory.getInstance()
350         .createLibraryElement(JpsElementFactory.getInstance().createLibraryReference(libraryName, parentReference));
351     }
352
353     @Override
354     public void save(JpsLibraryFilesPackagingElement element, Element tag) {
355       JpsLibraryReference reference = element.getLibraryReference();
356       JpsElementReference<? extends JpsCompositeElement> parentReference = reference.getParentReference();
357       tag.setAttribute("level", JpsLibraryTableSerializer.getLevelId(parentReference));
358       tag.setAttribute("name", reference.getLibraryName());
359       if (parentReference instanceof JpsModuleReference) {
360         tag.setAttribute("module-name", ((JpsModuleReference)parentReference).getModuleName());
361       }
362     }
363   }
364
365   private static class ArtifactOutputElementSerializer extends JpsPackagingElementSerializer<JpsArtifactOutputPackagingElement> {
366     ArtifactOutputElementSerializer() {
367       super("artifact", JpsArtifactOutputPackagingElement.class);
368     }
369
370     @Override
371     public JpsArtifactOutputPackagingElement load(Element element) {
372       return JpsPackagingElementFactory.getInstance()
373         .createArtifactOutput(JpsArtifactService.getInstance().createReference(element.getAttributeValue("artifact-name")));
374     }
375
376     @Override
377     public void save(JpsArtifactOutputPackagingElement element, Element tag) {
378       tag.setAttribute("artifact-name", element.getArtifactReference().getArtifactName());
379     }
380   }
381 }