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