/* * Copyright 2000-2016 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.library; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.JDOMUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.JpsDummyElement; import org.jetbrains.jps.model.JpsElement; import org.jetbrains.jps.model.JpsElementFactory; import org.jetbrains.jps.model.java.JpsJavaExtensionService; 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.JpsLibraryCollection; import org.jetbrains.jps.model.library.JpsLibraryRoot; import org.jetbrains.jps.model.library.JpsOrderRootType; import org.jetbrains.jps.model.library.sdk.JpsSdk; import org.jetbrains.jps.model.library.sdk.JpsSdkReference; import org.jetbrains.jps.model.library.sdk.JpsSdkType; import org.jetbrains.jps.model.module.JpsSdkReferencesTable; import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * @author nik */ public class JpsSdkTableSerializer { private static final Logger LOG = Logger.getInstance(JpsSdkTableSerializer.class); private static final JpsLibraryRootTypeSerializer[] PREDEFINED_ROOT_TYPE_SERIALIZERS = { new JpsLibraryRootTypeSerializer("classPath", JpsOrderRootType.COMPILED, true), new JpsLibraryRootTypeSerializer("sourcePath", JpsOrderRootType.SOURCES, true) }; private static final JpsSdkPropertiesSerializer<JpsDummyElement> JPS_JAVA_SDK_PROPERTIES_LOADER = new JpsSdkPropertiesSerializer<JpsDummyElement>("JavaSDK", JpsJavaSdkType.INSTANCE) { @NotNull @Override public JpsDummyElement loadProperties(Element propertiesElement) { return JpsElementFactory.getInstance().createDummyElement(); } @Override public void saveProperties(@NotNull JpsDummyElement properties, @NotNull Element element) { } }; private static final String JDK_TAG = "jdk"; private static final String NAME_TAG = "name"; private static final String TYPE_TAG = "type"; private static final String TYPE_ATTRIBUTE = "type"; private static final String ROOTS_TAG = "roots"; private static final String ROOT_TAG = "root"; private static final String VERSION_TAG = "version"; private static final String HOME_PATH_TAG = "homePath"; private static final String VALUE_ATTRIBUTE = "value"; private static final String COMPOSITE_TYPE = "composite"; private static final String SIMPLE_TYPE = "simple"; private static final String URL_ATTRIBUTE = "url"; private static final String ADDITIONAL_TAG = "additional"; public static void loadSdks(@Nullable Element sdkListElement, JpsLibraryCollection result) { for (Element sdkElement : JDOMUtil.getChildren(sdkListElement, JDK_TAG)) { result.addLibrary(loadSdk(sdkElement)); } } public static void saveSdks(JpsLibraryCollection libraryCollection, Element sdkListElement) { for (JpsLibrary library : libraryCollection.getLibraries()) { JpsElement properties = library.getProperties(); if (properties instanceof JpsSdk<?>) { Element sdkTag = new Element(JDK_TAG); saveSdk((JpsSdk<?>)properties, sdkTag); sdkListElement.addContent(sdkTag); } } } private static JpsLibrary loadSdk(Element sdkElement) { String name = getAttributeValue(sdkElement, NAME_TAG); String typeId = getAttributeValue(sdkElement, TYPE_TAG); LOG.debug("Loading " + typeId + " SDK '" + name + "'"); JpsSdkPropertiesSerializer<?> serializer = getSdkPropertiesSerializer(typeId); final JpsLibrary library = createSdk(name, serializer, sdkElement); final Element roots = sdkElement.getChild(ROOTS_TAG); for (Element rootTypeElement : JDOMUtil.getChildren(roots)) { JpsLibraryRootTypeSerializer rootTypeSerializer = getRootTypeSerializer(rootTypeElement.getName()); if (rootTypeSerializer != null) { for (Element rootElement : rootTypeElement.getChildren()) { loadRoots(rootElement, library, rootTypeSerializer.getType()); } } else { LOG.info("root type serializer not found for " + rootTypeElement.getName()); } } if (LOG.isDebugEnabled()) { List<File> files = library.getFiles(JpsOrderRootType.COMPILED); LOG.debug(name + " SDK classpath (" + files.size() + " roots):"); for (File file : files) { LOG.debug(" " + file.getAbsolutePath()); } } return library; } private static <P extends JpsElement> void saveSdk(final JpsSdk<P> sdk, Element sdkTag) { JpsLibrary library = sdk.getParent(); sdkTag.setAttribute("version", "2"); setAttributeValue(sdkTag, NAME_TAG, library.getName()); JpsSdkPropertiesSerializer<P> serializer = getSdkPropertiesSerializer(sdk.getSdkType()); setAttributeValue(sdkTag, TYPE_TAG, serializer.getTypeId()); String versionString = sdk.getVersionString(); if (versionString != null) { setAttributeValue(sdkTag, VERSION_TAG, versionString); } setAttributeValue(sdkTag, HOME_PATH_TAG, sdk.getHomePath()); Element rootsTag = new Element(ROOTS_TAG); for (JpsLibraryRootTypeSerializer rootTypeSerializer : getRootTypeSerializers()) { Element rootTypeTag = new Element(rootTypeSerializer.getTypeId()); Element compositeTag = new Element(ROOT_TAG); compositeTag.setAttribute(TYPE_ATTRIBUTE, COMPOSITE_TYPE); List<JpsLibraryRoot> roots = library.getRoots(rootTypeSerializer.getType()); for (JpsLibraryRoot root : roots) { compositeTag.addContent(new Element(ROOT_TAG).setAttribute(TYPE_ATTRIBUTE, SIMPLE_TYPE).setAttribute(URL_ATTRIBUTE, root.getUrl())); } rootTypeTag.addContent(compositeTag); rootsTag.addContent(rootTypeTag); } sdkTag.addContent(rootsTag); Element additionalTag = new Element(ADDITIONAL_TAG); serializer.saveProperties(sdk.getSdkProperties(), additionalTag); sdkTag.addContent(additionalTag); } private static void setAttributeValue(Element tag, final String tagName, final String value) { tag.addContent(new Element(tagName).setAttribute(VALUE_ATTRIBUTE, value)); } private static void loadRoots(Element rootElement, JpsLibrary library, JpsOrderRootType rootType) { final String type = rootElement.getAttributeValue(TYPE_ATTRIBUTE); if (type.equals(COMPOSITE_TYPE)) { for (Element element : rootElement.getChildren()) { loadRoots(element, library, rootType); } } else if (type.equals(SIMPLE_TYPE)) { library.addRoot(rootElement.getAttributeValue(URL_ATTRIBUTE), rootType); } } @Nullable private static JpsLibraryRootTypeSerializer getRootTypeSerializer(String typeId) { for (JpsLibraryRootTypeSerializer serializer : PREDEFINED_ROOT_TYPE_SERIALIZERS) { if (serializer.getTypeId().equals(typeId)) { return serializer; } } for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) { for (JpsLibraryRootTypeSerializer serializer : extension.getSdkRootTypeSerializers()) { if (serializer.getTypeId().equals(typeId)) { return serializer; } } } return null; } private static List<JpsLibraryRootTypeSerializer> getRootTypeSerializers() { List<JpsLibraryRootTypeSerializer> serializers = new ArrayList<>(Arrays.asList(PREDEFINED_ROOT_TYPE_SERIALIZERS)); for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) { serializers.addAll(extension.getSdkRootTypeSerializers()); } Collections.sort(serializers); return serializers; } private static <P extends JpsElement> JpsLibrary createSdk(String name, JpsSdkPropertiesSerializer<P> loader, Element sdkElement) { String versionString = getAttributeValue(sdkElement, VERSION_TAG); String homePath = getAttributeValue(sdkElement, HOME_PATH_TAG); Element propertiesTag = sdkElement.getChild(ADDITIONAL_TAG); P properties = loader.loadProperties(propertiesTag); return JpsElementFactory.getInstance().createSdk(name, homePath, versionString, loader.getType(), properties); } public static JpsSdkPropertiesSerializer<?> getSdkPropertiesSerializer(@Nullable String typeId) { for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) { for (JpsSdkPropertiesSerializer<?> loader : extension.getSdkPropertiesSerializers()) { if (loader.getTypeId().equals(typeId)) { return loader; } } } return JPS_JAVA_SDK_PROPERTIES_LOADER; } public static <P extends JpsElement> JpsSdkPropertiesSerializer<P> getSdkPropertiesSerializer(JpsSdkType<P> type) { for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) { for (JpsSdkPropertiesSerializer<?> loader : extension.getSdkPropertiesSerializers()) { if (loader.getType().equals(type)) { //noinspection unchecked return (JpsSdkPropertiesSerializer<P>)loader; } } } //noinspection unchecked return (JpsSdkPropertiesSerializer<P>)JPS_JAVA_SDK_PROPERTIES_LOADER; } @Nullable private static String getAttributeValue(Element element, String childName) { final Element child = element.getChild(childName); return child != null ? child.getAttributeValue(VALUE_ATTRIBUTE) : null; } public static JpsSdkType<?> getSdkType(@Nullable String typeId) { return getSdkPropertiesSerializer(typeId).getType(); } public static JpsSdkPropertiesSerializer<?> getLoader(JpsSdkType<?> type) { for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) { for (JpsSdkPropertiesSerializer<?> loader : extension.getSdkPropertiesSerializers()) { if (loader.getType().equals(type)) { return loader; } } } return JPS_JAVA_SDK_PROPERTIES_LOADER; } public static <P extends JpsElement> void setSdkReference(final JpsSdkReferencesTable table, String sdkName, JpsSdkType<P> sdkType) { JpsSdkReference<P> reference = JpsElementFactory.getInstance().createSdkReference(sdkName, sdkType); table.setSdkReference(sdkType, reference); if (sdkType instanceof JpsJavaSdkTypeWrapper) { JpsSdkReference<P> wrapperRef = JpsElementFactory.getInstance().createSdkReference(sdkName, sdkType); table.setSdkReference(JpsJavaSdkType.INSTANCE, JpsJavaExtensionService.getInstance().createWrappedJavaSdkReference((JpsJavaSdkTypeWrapper)sdkType, wrapperRef)); } } }