summaryrefslogtreecommitdiff
path: root/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/JpsJavaModelSerializerExtension.java
blob: 22188be46e2df883b51b3fa550388ce60e5577b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
/*
 * Copyright 2000-2013 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jetbrains.jps.model.serialization.java;

import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.text.StringUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.*;
import org.jetbrains.jps.model.java.*;
import org.jetbrains.jps.model.library.JpsOrderRootType;
import org.jetbrains.jps.model.module.JpsDependencyElement;
import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.model.module.JpsModuleReference;
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension;
import org.jetbrains.jps.model.serialization.JpsProjectExtensionSerializer;
import org.jetbrains.jps.model.serialization.artifact.JpsPackagingElementSerializer;
import org.jetbrains.jps.model.serialization.java.compiler.*;
import org.jetbrains.jps.model.serialization.library.JpsLibraryRootTypeSerializer;
import org.jetbrains.jps.model.serialization.module.JpsModuleRootModelSerializer;
import org.jetbrains.jps.model.serialization.module.JpsModuleSourceRootDummyPropertiesSerializer;
import org.jetbrains.jps.model.serialization.module.JpsModuleSourceRootPropertiesSerializer;

import java.util.Arrays;
import java.util.List;

/**
 * @author nik
 */
public class JpsJavaModelSerializerExtension extends JpsModelSerializerExtension {
  public static final String EXPORTED_ATTRIBUTE = "exported";
  public static final String SCOPE_ATTRIBUTE = "scope";
  public static final String OUTPUT_TAG = "output";
  public static final String URL_ATTRIBUTE = "url";
  public static final String LANGUAGE_LEVEL_ATTRIBUTE = "languageLevel";
  public static final String EXPLODED_TAG = "exploded";
  public static final String EXCLUDE_EXPLODED_TAG = "exclude-exploded";
  public static final String TEST_OUTPUT_TAG = "output-test";
  public static final String INHERIT_COMPILER_OUTPUT_ATTRIBUTE = "inherit-compiler-output";
  public static final String EXCLUDE_OUTPUT_TAG = "exclude-output";
  private static final String ANNOTATION_PATHS_TAG = "annotation-paths";
  private static final String JAVADOC_PATHS_TAG = "javadoc-paths";
  private static final String MODULE_LANGUAGE_LEVEL_ATTRIBUTE = "LANGUAGE_LEVEL";
  public static final String ROOT_TAG = "root";
  private static final String IS_GENERATED_ATTRIBUTE = "generated";
  public static final JavaSourceRootPropertiesSerializer JAVA_SOURCE_ROOT_PROPERTIES_SERIALIZER =
    new JavaSourceRootPropertiesSerializer(JavaSourceRootType.SOURCE, JpsModuleRootModelSerializer.JAVA_SOURCE_ROOT_TYPE_ID);

  @Override
  public void loadRootModel(@NotNull JpsModule module, @NotNull Element rootModel) {
    loadExplodedDirectoryExtension(module, rootModel);
    loadJavaModuleExtension(module, rootModel);
  }

  @Override
  public void saveRootModel(@NotNull JpsModule module, @NotNull Element rootModel) {
    saveExplodedDirectoryExtension(module, rootModel);
    saveJavaModuleExtension(module, rootModel);
  }

  @NotNull
  @Override
  public List<? extends JpsProjectExtensionSerializer> getProjectExtensionSerializers() {
    return Arrays.asList(new JavaProjectExtensionSerializer(),
                         new JpsJavaCompilerConfigurationSerializer(),
                         new JpsJavaCompilerWorkspaceConfigurationSerializer(),
                         new JpsJavaCompilerOptionsSerializer("JavacSettings", "Javac"),
                         new JpsEclipseCompilerOptionsSerializer("EclipseCompilerSettings", "Eclipse"),
                         new RmicCompilerOptionsSerializer("RmicSettings", "Rmic"));
  }

  @NotNull
  @Override
  public List<? extends JpsModuleSourceRootPropertiesSerializer<?>> getModuleSourceRootPropertiesSerializers() {
    return Arrays.asList(JAVA_SOURCE_ROOT_PROPERTIES_SERIALIZER,
                         new JavaSourceRootPropertiesSerializer(JavaSourceRootType.TEST_SOURCE, JpsModuleRootModelSerializer.JAVA_TEST_ROOT_TYPE_ID),
                         new JpsModuleSourceRootDummyPropertiesSerializer(JavaResourceRootType.RESOURCE, "java-resource"),
                         new JpsModuleSourceRootDummyPropertiesSerializer(JavaResourceRootType.TEST_RESOURCE, "java-test-resource"));
  }

  @Override
  public void loadModuleDependencyProperties(JpsDependencyElement dependency, Element entry) {
    boolean exported = entry.getAttributeValue(EXPORTED_ATTRIBUTE) != null;
    String scopeName = entry.getAttributeValue(SCOPE_ATTRIBUTE);
    JpsJavaDependencyScope scope = null;
    try {
      scope = scopeName != null ? JpsJavaDependencyScope.valueOf(scopeName) : JpsJavaDependencyScope.COMPILE;
    }
    catch (IllegalArgumentException e) {
      scope = JpsJavaDependencyScope.COMPILE;
    }

    final JpsJavaDependencyExtension extension = getService().getOrCreateDependencyExtension(dependency);
    extension.setExported(exported);
    extension.setScope(scope);
  }

  @Override
  public void saveModuleDependencyProperties(JpsDependencyElement dependency, Element orderEntry) {
    JpsJavaDependencyExtension extension = getService().getDependencyExtension(dependency);
    if (extension != null) {
      if (extension.isExported()) {
        orderEntry.setAttribute(EXPORTED_ATTRIBUTE, "");
      }
      JpsJavaDependencyScope scope = extension.getScope();
      if (scope != JpsJavaDependencyScope.COMPILE) {
        orderEntry.setAttribute(SCOPE_ATTRIBUTE, scope.name());
      }
    }
  }

  @Override
  public List<JpsLibraryRootTypeSerializer> getLibraryRootTypeSerializers() {
    return Arrays.asList(new JpsLibraryRootTypeSerializer("JAVADOC", JpsOrderRootType.DOCUMENTATION, true),
                         new JpsLibraryRootTypeSerializer("ANNOTATIONS", JpsAnnotationRootType.INSTANCE, false),
                         new JpsLibraryRootTypeSerializer("NATIVE", JpsNativeLibraryRootType.INSTANCE, false));
  }

  @NotNull
  @Override
  public List<JpsLibraryRootTypeSerializer> getSdkRootTypeSerializers() {
    return Arrays.asList(new JpsLibraryRootTypeSerializer("javadocPath", JpsOrderRootType.DOCUMENTATION, true),
                         new JpsLibraryRootTypeSerializer("annotationsPath", JpsAnnotationRootType.INSTANCE, true));
  }

  @NotNull
  @Override
  public List<? extends JpsPackagingElementSerializer<?>> getPackagingElementSerializers() {
    return Arrays.asList(new JpsModuleOutputPackagingElementSerializer(), new JpsTestModuleOutputPackagingElementSerializer());
  }

  private static void loadExplodedDirectoryExtension(JpsModule module, Element rootModelComponent) {
    final Element exploded = rootModelComponent.getChild(EXPLODED_TAG);
    if (exploded != null) {
      final ExplodedDirectoryModuleExtension extension = getService().getOrCreateExplodedDirectoryExtension(module);
      extension.setExcludeExploded(rootModelComponent.getChild(EXCLUDE_EXPLODED_TAG) != null);
      extension.setExplodedUrl(exploded.getAttributeValue(URL_ATTRIBUTE));
    }
  }

  private static void saveExplodedDirectoryExtension(JpsModule module, Element rootModelElement) {
    ExplodedDirectoryModuleExtension extension = getService().getExplodedDirectoryExtension(module);
    if (extension != null) {
      if (extension.isExcludeExploded()) {
        rootModelElement.addContent(0, new Element(EXCLUDE_EXPLODED_TAG));
      }
      rootModelElement.addContent(0, new Element(EXPLODED_TAG).setAttribute(URL_ATTRIBUTE, extension.getExplodedUrl()));
    }
  }

  private static void loadJavaModuleExtension(JpsModule module, Element rootModelComponent) {
    final JpsJavaModuleExtension extension = getService().getOrCreateModuleExtension(module);
    final Element outputTag = rootModelComponent.getChild(OUTPUT_TAG);
    String outputUrl = outputTag != null ? outputTag.getAttributeValue(URL_ATTRIBUTE) : null;
    extension.setOutputUrl(outputUrl);
    final Element testOutputTag = rootModelComponent.getChild(TEST_OUTPUT_TAG);
    String testOutputUrl = testOutputTag != null ? testOutputTag.getAttributeValue(URL_ATTRIBUTE) : null;
    extension.setTestOutputUrl(StringUtil.isEmpty(testOutputUrl) ? outputUrl : testOutputUrl);

    extension.setInheritOutput(Boolean.parseBoolean(rootModelComponent.getAttributeValue(INHERIT_COMPILER_OUTPUT_ATTRIBUTE)));
    extension.setExcludeOutput(rootModelComponent.getChild(EXCLUDE_OUTPUT_TAG) != null);

    final String languageLevel = rootModelComponent.getAttributeValue(MODULE_LANGUAGE_LEVEL_ATTRIBUTE);
    if (languageLevel != null) {
      extension.setLanguageLevel(LanguageLevel.valueOf(languageLevel));
    }

    loadAdditionalRoots(rootModelComponent, ANNOTATION_PATHS_TAG, extension.getAnnotationRoots());
    loadAdditionalRoots(rootModelComponent, JAVADOC_PATHS_TAG, extension.getJavadocRoots());
  }

  private static void saveJavaModuleExtension(JpsModule module, Element rootModelComponent) {
    JpsJavaModuleExtension extension = getService().getModuleExtension(module);
    if (extension == null) return;
    if (extension.isExcludeOutput()) {
      rootModelComponent.addContent(0, new Element(EXCLUDE_OUTPUT_TAG));
    }

    String testOutputUrl = extension.getTestOutputUrl();
    if (testOutputUrl != null) {
      rootModelComponent.addContent(0, new Element(TEST_OUTPUT_TAG).setAttribute(URL_ATTRIBUTE, testOutputUrl));
    }

    String outputUrl = extension.getOutputUrl();
    if (outputUrl != null) {
      rootModelComponent.addContent(0, new Element(OUTPUT_TAG).setAttribute(URL_ATTRIBUTE, outputUrl));
    }

    LanguageLevel languageLevel = extension.getLanguageLevel();
    if (languageLevel != null) {
      rootModelComponent.setAttribute(MODULE_LANGUAGE_LEVEL_ATTRIBUTE, languageLevel.name());
    }
    rootModelComponent.setAttribute(INHERIT_COMPILER_OUTPUT_ATTRIBUTE, String.valueOf(extension.isInheritOutput()));
    saveAdditionalRoots(rootModelComponent, JAVADOC_PATHS_TAG, extension.getJavadocRoots());
    saveAdditionalRoots(rootModelComponent, ANNOTATION_PATHS_TAG, extension.getAnnotationRoots());
  }

  private static void loadAdditionalRoots(Element rootModelComponent, final String rootsTagName, final JpsUrlList result) {
    final Element roots = rootModelComponent.getChild(rootsTagName);
    for (Element root : JDOMUtil.getChildren(roots, ROOT_TAG)) {
      result.addUrl(root.getAttributeValue(URL_ATTRIBUTE));
    }
  }

  private static void saveAdditionalRoots(Element rootModelComponent, final String rootsTagName, final JpsUrlList list) {
    List<String> urls = list.getUrls();
    if (!urls.isEmpty()) {
      Element roots = new Element(rootsTagName);
      for (String url : urls) {
        roots.addContent(new Element(ROOT_TAG).setAttribute(URL_ATTRIBUTE, url));
      }
      rootModelComponent.addContent(roots);
    }
  }

  private static JpsJavaExtensionService getService() {
    return JpsJavaExtensionService.getInstance();
  }

  private static class JpsModuleOutputPackagingElementSerializer
    extends JpsPackagingElementSerializer<JpsProductionModuleOutputPackagingElement> {
    private JpsModuleOutputPackagingElementSerializer() {
      super("module-output", JpsProductionModuleOutputPackagingElement.class);
    }

    @Override
    public JpsProductionModuleOutputPackagingElement load(Element element) {
      JpsModuleReference reference = JpsElementFactory.getInstance().createModuleReference(element.getAttributeValue("name"));
      return getService().createProductionModuleOutput(reference);
    }

    @Override
    public void save(JpsProductionModuleOutputPackagingElement element, Element tag) {
      tag.setAttribute("name", element.getModuleReference().getModuleName());
    }
  }

  private static class JpsTestModuleOutputPackagingElementSerializer extends JpsPackagingElementSerializer<JpsTestModuleOutputPackagingElement> {
    private JpsTestModuleOutputPackagingElementSerializer() {
      super("module-test-output", JpsTestModuleOutputPackagingElement.class);
    }

    @Override
    public JpsTestModuleOutputPackagingElement load(Element element) {
      JpsModuleReference reference = JpsElementFactory.getInstance().createModuleReference(element.getAttributeValue("name"));
      return getService().createTestModuleOutput(reference);
    }

    @Override
    public void save(JpsTestModuleOutputPackagingElement element, Element tag) {
      tag.setAttribute("name", element.getModuleReference().getModuleName());
    }
  }

  private static class JavaProjectExtensionSerializer extends JpsProjectExtensionSerializer {
    public JavaProjectExtensionSerializer() {
      super(null, "ProjectRootManager");
    }

    @Override
    public void loadExtension(@NotNull JpsProject project, @NotNull Element componentTag) {
      JpsJavaProjectExtension extension = getService().getOrCreateProjectExtension(project);
      final Element output = componentTag.getChild(OUTPUT_TAG);
      if (output != null) {
        String url = output.getAttributeValue(URL_ATTRIBUTE);
        if (url != null) {
          extension.setOutputUrl(url);
        }
      }
      String languageLevel = componentTag.getAttributeValue(LANGUAGE_LEVEL_ATTRIBUTE);
      if (languageLevel != null) {
        extension.setLanguageLevel(LanguageLevel.valueOf(languageLevel));
      }
    }

    @Override
    public void saveExtension(@NotNull JpsProject project, @NotNull Element componentTag) {
      JpsJavaProjectExtension extension = getService().getProjectExtension(project);
      if (extension == null) return;

      String outputUrl = extension.getOutputUrl();
      if (outputUrl != null) {
        componentTag.addContent(new Element(OUTPUT_TAG).setAttribute(URL_ATTRIBUTE, outputUrl));
      }
      LanguageLevel level = extension.getLanguageLevel();
      componentTag.setAttribute(LANGUAGE_LEVEL_ATTRIBUTE, level.name());
      componentTag.setAttribute("assert-keyword", Boolean.toString(level.compareTo(LanguageLevel.JDK_1_4) >= 0));
      componentTag.setAttribute("jdk-15", Boolean.toString(level.compareTo(LanguageLevel.JDK_1_5) >= 0));
    }
  }

  private static class JavaSourceRootPropertiesSerializer extends JpsModuleSourceRootPropertiesSerializer<JavaSourceRootProperties> {
    private JavaSourceRootPropertiesSerializer(JpsModuleSourceRootType<JavaSourceRootProperties> type, String typeId) {
      super(type, typeId);
    }

    @Override
    public JavaSourceRootProperties loadProperties(@NotNull Element sourceRootTag) {
      String packagePrefix = StringUtil.notNullize(sourceRootTag.getAttributeValue(JpsModuleRootModelSerializer.PACKAGE_PREFIX_ATTRIBUTE));
      boolean isGenerated = Boolean.parseBoolean(sourceRootTag.getAttributeValue(IS_GENERATED_ATTRIBUTE));
      return getService().createSourceRootProperties(packagePrefix, isGenerated);
    }

    @Override
    public void saveProperties(@NotNull JavaSourceRootProperties properties, @NotNull Element sourceRootTag) {
      String isTestSource = Boolean.toString(getType().equals(JavaSourceRootType.TEST_SOURCE));
      sourceRootTag.setAttribute(JpsModuleRootModelSerializer.IS_TEST_SOURCE_ATTRIBUTE, isTestSource);
      String packagePrefix = properties.getPackagePrefix();
      if (!packagePrefix.isEmpty()) {
        sourceRootTag.setAttribute(JpsModuleRootModelSerializer.PACKAGE_PREFIX_ATTRIBUTE, packagePrefix);
      }
      if (properties.isForGeneratedSources()) {
        sourceRootTag.setAttribute(IS_GENERATED_ATTRIBUTE, Boolean.TRUE.toString());
      }
    }
  }
}