blob: 211d8d1a5bbdb65dc45a0ba5fa7c2792b47f2990 [file] [log] [blame]
/*
* Copyright 2000-2012 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.module;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.text.UniqueNameGenerator;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.JpsCompositeElement;
import org.jetbrains.jps.model.JpsElement;
import org.jetbrains.jps.model.JpsElementFactory;
import org.jetbrains.jps.model.JpsElementReference;
import org.jetbrains.jps.model.java.JpsJavaSdkType;
import org.jetbrains.jps.model.java.JpsJavaSdkTypeWrapper;
import org.jetbrains.jps.model.library.JpsLibrary;
import org.jetbrains.jps.model.library.JpsLibraryReference;
import org.jetbrains.jps.model.library.sdk.JpsSdkReference;
import org.jetbrains.jps.model.library.sdk.JpsSdkType;
import org.jetbrains.jps.model.module.*;
import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension;
import org.jetbrains.jps.model.serialization.java.JpsJavaModelSerializerExtension;
import org.jetbrains.jps.model.serialization.library.JpsLibraryTableSerializer;
import org.jetbrains.jps.model.serialization.library.JpsSdkTableSerializer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.intellij.openapi.util.JDOMUtil.getChildren;
/**
* @author nik
*/
public class JpsModuleRootModelSerializer {
private static final Logger LOG = Logger.getInstance(JpsModuleRootModelSerializer.class);
public static final String URL_ATTRIBUTE = "url";
public static final String CONTENT_TAG = "content";
public static final String SOURCE_FOLDER_TAG = "sourceFolder";
public static final String PACKAGE_PREFIX_ATTRIBUTE = "packagePrefix";
public static final String IS_TEST_SOURCE_ATTRIBUTE = "isTestSource";
public static final String EXCLUDE_FOLDER_TAG = "excludeFolder";
public static final String ORDER_ENTRY_TAG = "orderEntry";
public static final String TYPE_ATTRIBUTE = "type";
public static final String SOURCE_FOLDER_TYPE = "sourceFolder";
public static final String JDK_TYPE = "jdk";
public static final String JDK_NAME_ATTRIBUTE = "jdkName";
public static final String JDK_TYPE_ATTRIBUTE = "jdkType";
public static final String INHERITED_JDK_TYPE = "inheritedJdk";
public static final String LIBRARY_TYPE = "library";
public static final String NAME_ATTRIBUTE = "name";
public static final String LEVEL_ATTRIBUTE = "level";
public static final String LIBRARY_TAG = "library";
public static final String MODULE_LIBRARY_TYPE = "module-library";
public static final String MODULE_TYPE = "module";
public static final String MODULE_NAME_ATTRIBUTE = "module-name";
private static final String SOURCE_ROOT_TYPE_ATTRIBUTE = "type";
public static final String JAVA_SOURCE_ROOT_TYPE_ID = "java-source";
public static final String JAVA_TEST_ROOT_TYPE_ID = "java-test";
private static final String GENERATED_LIBRARY_NAME_PREFIX = "#";
public static void loadRootModel(JpsModule module, @Nullable Element rootModelComponent, @Nullable JpsSdkType<?> projectSdkType) {
if (rootModelComponent == null) return;
for (Element contentElement : getChildren(rootModelComponent, CONTENT_TAG)) {
final String url = contentElement.getAttributeValue(URL_ATTRIBUTE);
module.getContentRootsList().addUrl(url);
for (Element sourceElement : getChildren(contentElement, SOURCE_FOLDER_TAG)) {
module.addSourceRoot(loadSourceRoot(sourceElement));
}
for (Element excludeElement : getChildren(contentElement, EXCLUDE_FOLDER_TAG)) {
module.getExcludeRootsList().addUrl(excludeElement.getAttributeValue(URL_ATTRIBUTE));
}
}
final JpsDependenciesList dependenciesList = module.getDependenciesList();
dependenciesList.clear();
final JpsElementFactory elementFactory = JpsElementFactory.getInstance();
UniqueNameGenerator nameGenerator = new UniqueNameGenerator();
for (Element orderEntry : getChildren(rootModelComponent, ORDER_ENTRY_TAG)) {
String type = orderEntry.getAttributeValue(TYPE_ATTRIBUTE);
if (SOURCE_FOLDER_TYPE.equals(type)) {
dependenciesList.addModuleSourceDependency();
}
else if (JDK_TYPE.equals(type)) {
String sdkName = orderEntry.getAttributeValue(JDK_NAME_ATTRIBUTE);
String sdkTypeId = orderEntry.getAttributeValue(JDK_TYPE_ATTRIBUTE);
final JpsSdkType<?> sdkType = JpsSdkTableSerializer.getSdkType(sdkTypeId);
dependenciesList.addSdkDependency(sdkType);
JpsSdkTableSerializer.setSdkReference(module.getSdkReferencesTable(), sdkName, sdkType);
if (sdkType instanceof JpsJavaSdkTypeWrapper) {
dependenciesList.addSdkDependency(JpsJavaSdkType.INSTANCE);
}
}
else if (INHERITED_JDK_TYPE.equals(type)) {
final JpsSdkType<?> sdkType = projectSdkType != null? projectSdkType : JpsJavaSdkType.INSTANCE;
dependenciesList.addSdkDependency(sdkType);
if (sdkType instanceof JpsJavaSdkTypeWrapper) {
dependenciesList.addSdkDependency(JpsJavaSdkType.INSTANCE);
}
}
else if (LIBRARY_TYPE.equals(type)) {
String name = orderEntry.getAttributeValue(NAME_ATTRIBUTE);
String level = orderEntry.getAttributeValue(LEVEL_ATTRIBUTE);
final JpsLibraryDependency dependency =
dependenciesList.addLibraryDependency(elementFactory.createLibraryReference(name, JpsLibraryTableSerializer
.createLibraryTableReference(level)));
loadModuleDependencyProperties(dependency, orderEntry);
}
else if (MODULE_LIBRARY_TYPE.equals(type)) {
final Element moduleLibraryElement = orderEntry.getChild(LIBRARY_TAG);
String name = moduleLibraryElement.getAttributeValue(NAME_ATTRIBUTE);
if (name == null) {
name = GENERATED_LIBRARY_NAME_PREFIX;
}
String uniqueName = nameGenerator.generateUniqueName(name);
final JpsLibrary library = JpsLibraryTableSerializer.loadLibrary(moduleLibraryElement, uniqueName);
module.addModuleLibrary(library);
final JpsLibraryDependency dependency = dependenciesList.addLibraryDependency(library);
loadModuleDependencyProperties(dependency, orderEntry);
}
else if (MODULE_TYPE.equals(type)) {
String name = orderEntry.getAttributeValue(MODULE_NAME_ATTRIBUTE);
final JpsModuleDependency dependency = dependenciesList.addModuleDependency(elementFactory.createModuleReference(name));
loadModuleDependencyProperties(dependency, orderEntry);
}
}
for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
extension.loadRootModel(module, rootModelComponent);
}
}
@NotNull
public static JpsModuleSourceRoot loadSourceRoot(Element sourceElement) {
final String sourceUrl = sourceElement.getAttributeValue(URL_ATTRIBUTE);
JpsModuleSourceRootPropertiesSerializer<?> serializer = getSourceRootPropertiesSerializer(sourceElement);
return createSourceRoot(sourceUrl, serializer, sourceElement);
}
@NotNull
private static <P extends JpsElement> JpsModuleSourceRoot createSourceRoot(@NotNull String url,
@NotNull JpsModuleSourceRootPropertiesSerializer<P> serializer,
@NotNull Element sourceElement) {
return JpsElementFactory.getInstance().createModuleSourceRoot(url, serializer.getType(), serializer.loadProperties(sourceElement));
}
@NotNull
private static JpsModuleSourceRootPropertiesSerializer<?> getSourceRootPropertiesSerializer(@NotNull Element sourceElement) {
String typeAttribute = sourceElement.getAttributeValue(SOURCE_ROOT_TYPE_ATTRIBUTE);
if (typeAttribute == null) {
typeAttribute = Boolean.parseBoolean(sourceElement.getAttributeValue(IS_TEST_SOURCE_ATTRIBUTE)) ? JAVA_TEST_ROOT_TYPE_ID : JAVA_SOURCE_ROOT_TYPE_ID;
}
for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
for (JpsModuleSourceRootPropertiesSerializer<?> serializer : extension.getModuleSourceRootPropertiesSerializers()) {
if (serializer.getTypeId().equals(typeAttribute)) {
return serializer;
}
}
}
LOG.warn("Unknown module source root type " + typeAttribute);
return JpsJavaModelSerializerExtension.JAVA_SOURCE_ROOT_PROPERTIES_SERIALIZER;
}
public static void saveRootModel(JpsModule module, Element rootModelElement) {
List<JpsModuleSourceRoot> sourceRoots = module.getSourceRoots();
List<String> excludedUrls = getSortedList(module.getExcludeRootsList().getUrls());
for (String url : getSortedList(module.getContentRootsList().getUrls())) {
Element contentElement = new Element(CONTENT_TAG);
contentElement.setAttribute(URL_ATTRIBUTE, url);
rootModelElement.addContent(contentElement);
for (JpsModuleSourceRoot root : sourceRoots) {
if (FileUtil.startsWith(root.getUrl(), url)) {
saveSourceRoot(contentElement, root.asTyped().getUrl(), root.asTyped());
}
}
for (String excludedUrl : excludedUrls) {
if (FileUtil.startsWith(excludedUrl, url)) {
Element element = new Element(EXCLUDE_FOLDER_TAG).setAttribute(URL_ATTRIBUTE, excludedUrl);
contentElement.addContent(element);
}
}
}
for (JpsDependencyElement dependency : module.getDependenciesList().getDependencies()) {
if (dependency instanceof JpsModuleSourceDependency) {
rootModelElement.addContent(createDependencyElement(SOURCE_FOLDER_TYPE).setAttribute("forTests", "false"));
}
else if (dependency instanceof JpsSdkDependency) {
JpsSdkType<?> sdkType = ((JpsSdkDependency)dependency).getSdkType();
JpsSdkReferencesTable table = module.getSdkReferencesTable();
JpsSdkReference<?> reference = table.getSdkReference(sdkType);
if (reference == null) {
rootModelElement.addContent(createDependencyElement(INHERITED_JDK_TYPE));
}
else {
Element element = createDependencyElement(JDK_TYPE);
element.setAttribute(JDK_NAME_ATTRIBUTE, reference.getSdkName());
element.setAttribute(JDK_TYPE_ATTRIBUTE, JpsSdkTableSerializer.getLoader(sdkType).getTypeId());
rootModelElement.addContent(element);
}
}
else if (dependency instanceof JpsLibraryDependency) {
JpsLibraryReference reference = ((JpsLibraryDependency)dependency).getLibraryReference();
JpsElementReference<? extends JpsCompositeElement> parentReference = reference.getParentReference();
Element element;
if (parentReference instanceof JpsModuleReference) {
element = createDependencyElement(MODULE_LIBRARY_TYPE);
saveModuleDependencyProperties(dependency, element);
Element libraryElement = new Element(LIBRARY_TAG);
JpsLibrary library = reference.resolve();
String libraryName = library.getName();
JpsLibraryTableSerializer.saveLibrary(library, libraryElement, isGeneratedName(libraryName) ? null : libraryName);
element.addContent(libraryElement);
}
else {
element = createDependencyElement(LIBRARY_TYPE);
saveModuleDependencyProperties(dependency, element);
element.setAttribute(NAME_ATTRIBUTE, reference.getLibraryName());
element.setAttribute(LEVEL_ATTRIBUTE, JpsLibraryTableSerializer.getLevelId(parentReference));
}
rootModelElement.addContent(element);
}
else if (dependency instanceof JpsModuleDependency) {
Element element = createDependencyElement(MODULE_TYPE);
element.setAttribute(MODULE_NAME_ATTRIBUTE, ((JpsModuleDependency)dependency).getModuleReference().getModuleName());
saveModuleDependencyProperties(dependency, element);
rootModelElement.addContent(element);
}
}
for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
extension.saveRootModel(module, rootModelElement);
}
}
public static <P extends JpsElement> void saveSourceRoot(@NotNull Element contentElement,
final @NotNull String rootUrl,
@NotNull JpsTypedModuleSourceRoot<P> root) {
Element sourceElement = new Element(SOURCE_FOLDER_TAG);
sourceElement.setAttribute(URL_ATTRIBUTE, rootUrl);
JpsModuleSourceRootPropertiesSerializer<P> serializer = getSerializer(root.getRootType());
if (serializer != null) {
String typeId = serializer.getTypeId();
if (!typeId.equals(JAVA_SOURCE_ROOT_TYPE_ID) && !typeId.equals(JAVA_TEST_ROOT_TYPE_ID)) {
sourceElement.setAttribute(SOURCE_ROOT_TYPE_ATTRIBUTE, typeId);
}
serializer.saveProperties(root.getProperties(), sourceElement);
}
contentElement.addContent(sourceElement);
}
@Nullable
private static <P extends JpsElement> JpsModuleSourceRootPropertiesSerializer<P> getSerializer(JpsModuleSourceRootType<P> type) {
for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
for (JpsModuleSourceRootPropertiesSerializer<?> serializer : extension.getModuleSourceRootPropertiesSerializers()) {
if (serializer.getType().equals(type)) {
return (JpsModuleSourceRootPropertiesSerializer<P>)serializer;
}
}
}
return null;
}
private static boolean isGeneratedName(String libraryName) {
return libraryName.startsWith(GENERATED_LIBRARY_NAME_PREFIX);
}
private static Element createDependencyElement(final String type) {
return new Element(ORDER_ENTRY_TAG).setAttribute(TYPE_ATTRIBUTE, type);
}
private static List<String> getSortedList(final List<String> list) {
List<String> strings = new ArrayList<String>(list);
Collections.sort(strings);
return strings;
}
private static void loadModuleDependencyProperties(JpsDependencyElement dependency, Element orderEntry) {
for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
extension.loadModuleDependencyProperties(dependency, orderEntry);
}
}
private static void saveModuleDependencyProperties(JpsDependencyElement dependency, Element orderEntry) {
for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
extension.saveModuleDependencyProperties(dependency, orderEntry);
}
}
}