| /* |
| * 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); |
| } |
| } |
| } |