package jetbrains.mps.project.persistence; /*Generated by MPS */ import org.apache.log4j.Logger; import org.apache.log4j.LogManager; import jetbrains.mps.project.structure.modules.ModuleDescriptor; import org.jdom.Element; import jetbrains.mps.util.xml.XmlUtil; import jetbrains.mps.internal.collections.runtime.Sequence; import jetbrains.mps.internal.collections.runtime.IVisitor; import org.jetbrains.mps.openapi.language.SLanguage; import jetbrains.mps.smodel.adapter.structure.language.SLanguageAdapter; import jetbrains.mps.smodel.adapter.ids.SLanguageId; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import org.jetbrains.mps.openapi.module.SModuleReference; import org.jetbrains.mps.openapi.persistence.PersistenceFacade; import jetbrains.mps.project.structure.modules.LanguageDescriptor; import jetbrains.mps.project.structure.modules.Dependency; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.Map; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Set; import jetbrains.mps.internal.collections.runtime.SetSequence; import jetbrains.mps.internal.collections.runtime.ISelector; import java.util.List; import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes; import org.jetbrains.mps.openapi.module.SDependencyScope; import java.util.Collection; import jetbrains.mps.internal.collections.runtime.CollectionSequence; import jetbrains.mps.project.structure.model.ModelRootDescriptor; import jetbrains.mps.util.MacroHelper; import org.jetbrains.mps.openapi.persistence.Memento; import jetbrains.mps.persistence.MementoImpl; import org.apache.log4j.Level; import jetbrains.mps.project.structure.modules.ModuleFacetDescriptor; import org.jdom.Attribute; import jetbrains.mps.internal.collections.runtime.IWhereFilter; import jetbrains.mps.vfs.IFile; import jetbrains.mps.util.FileUtil; import jetbrains.mps.project.ModuleId; import java.io.InputStreamReader; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.io.IOException; public class ModuleDescriptorPersistence { private static final Logger LOG = LogManager.getLogger(ModuleDescriptorPersistence.class); private static final String HEADER_PATTERN = ".*<(language|dev-kit|solution)[^>]+(namespace|name)=\\\"([^\"]+)\\\"[^>]+uuid=\\\"([^\"]+)\\\".*"; private ModuleDescriptorPersistence() { } public static void loadDependencies(final ModuleDescriptor descriptor, Element root) { descriptor.getDependencies().addAll(loadDependenciesList(XmlUtil.first(root, "dependencies"))); descriptor.setHasLanguageVersions(!(root.getChildren("languageVersions").isEmpty())); Sequence.fromIterable(XmlUtil.children(XmlUtil.first(root, "languageVersions"), "language")).visitAll(new IVisitor<Element>() { public void visit(Element it) { String slang = it.getAttributeValue("slang"); SLanguage lang; if (slang != null) { lang = SLanguageAdapter.deserialize(slang); } else { // support old format using id+name pair, used before 3.4 SLanguageId id = SLanguageId.deserialize(it.getAttributeValue("id")); String name = it.getAttributeValue("fqName"); lang = MetaAdapterFactory.getLanguage(id, name); } descriptor.getLanguageVersions().put(lang, Integer.parseInt(it.getAttributeValue("version"))); } }); descriptor.setHasDependencyVersions(!(root.getChildren("dependencyVersions").isEmpty())); Sequence.fromIterable(XmlUtil.children(XmlUtil.first(root, "dependencyVersions"), "module")).visitAll(new IVisitor<Element>() { public void visit(Element it) { SModuleReference id = PersistenceFacade.getInstance().createModuleReference(it.getAttributeValue("reference")); descriptor.getDependencyVersions().put(id, Integer.parseInt(it.getAttributeValue("version"))); } }); if (descriptor instanceof LanguageDescriptor) { LanguageDescriptor ld = (LanguageDescriptor) descriptor; Element runtimeXML = XmlUtil.first(root, "runtime"); if (runtimeXML != null) { for (Dependency dep : ListSequence.fromList(loadDependenciesList(runtimeXML))) { ld.getRuntimeModules().add(dep.getModuleRef()); } } } } public static void saveDependencies(Element result, ModuleDescriptor descriptor) { if (!(descriptor.getDependencies().isEmpty())) { Element dependencies = new Element("dependencies"); saveDependencyList(dependencies, descriptor.getDependencies()); result.addContent(dependencies); } Map<SLanguage, Integer> lver = descriptor.getLanguageVersions(); ArrayList<SLanguage> langs = new ArrayList<SLanguage>(lver.keySet()); Collections.sort(langs, new Comparator<SLanguage>() { public int compare(SLanguage p0, SLanguage p1) { return p0.getQualifiedName().compareTo(p1.getQualifiedName()); } }); Element languageVersions = new Element("languageVersions"); for (SLanguage l : langs) { Element languageVersion = new Element("language"); languageVersion.setAttribute("slang", ((SLanguageAdapter) l).serialize()); languageVersion.setAttribute("version", String.valueOf(lver.get(l))); languageVersions.addContent(languageVersion); } result.addContent(languageVersions); Map<SModuleReference, Integer> depVer = descriptor.getDependencyVersions(); ArrayList<SModuleReference> deps = new ArrayList<SModuleReference>(depVer.keySet()); Collections.sort(deps, new Comparator<SModuleReference>() { public int compare(SModuleReference p0, SModuleReference p1) { return p0.getModuleName().compareTo(p1.getModuleName()); } }); Element dependencyVersions = new Element("dependencyVersions"); for (SModuleReference ref : deps) { Element moduleVersion = new Element("module"); moduleVersion.setAttribute("reference", ref.toString()); moduleVersion.setAttribute("version", String.valueOf(depVer.get(ref))); dependencyVersions.addContent(moduleVersion); } result.addContent(dependencyVersions); if (descriptor instanceof LanguageDescriptor) { LanguageDescriptor ld = ((LanguageDescriptor) descriptor); if (!(ld.getRuntimeModules().isEmpty())) { Element runtime = new Element("runtime"); Set<SModuleReference> runtimeModules = ld.getRuntimeModules(); saveDependencyList(runtime, SetSequence.fromSet(runtimeModules).select(new ISelector<SModuleReference, Dependency>() { public Dependency select(SModuleReference it) { return new Dependency(it, false); } }).toListSequence()); result.addContent(runtime); } } } public static List<Dependency> loadDependenciesList(Element depElement) { return Sequence.fromIterable(XmlUtil.children(depElement, "dependency")).select(new ISelector<Element, Dependency>() { public Dependency select(final Element d) { return new _FunctionTypes._return_P0_E0<Dependency>() { public Dependency invoke() { final Dependency result_dxyzb6_a0a0a0a0a0a8 = new Dependency(); final SModuleReference result_dxyzb6_a0a0a0a0a0a0a8 = PersistenceFacade.getInstance().createModuleReference(d.getText()); result_dxyzb6_a0a0a0a0a0a8.setModuleRef(result_dxyzb6_a0a0a0a0a0a0a8); final boolean result_dxyzb6_a1a0a0a0a0a0a8 = XmlUtil.booleanWithDefault(d, "reexport", true); result_dxyzb6_a0a0a0a0a0a8.setReexport(result_dxyzb6_a1a0a0a0a0a0a8); SDependencyScope s = SDependencyScope.fromIdentity(d.getAttributeValue("scope")); final SDependencyScope result_dxyzb6_a3a0a0a0a0a0a8 = (s == null ? SDependencyScope.DEFAULT : s); result_dxyzb6_a0a0a0a0a0a8.setScope(result_dxyzb6_a3a0a0a0a0a0a8); return result_dxyzb6_a0a0a0a0a0a8; } }.invoke(); } }).toListSequence(); } private static void saveDependencyList(Element result, Collection<Dependency> dependencies) { for (Dependency md : CollectionSequence.fromCollection(dependencies)) { Element child = new Element("dependency"); child.setAttribute("reexport", Boolean.toString(md.isReexport())); child.setText(md.getModuleRef().toString()); if (md.getScope() != SDependencyScope.DEFAULT) { // the only reason not to serialize DEFIAULT for now is to avoid extra diff with existing descriptors meanwhile // Once there's migration action, it might be reasonable to serialize each scope child.setAttribute("scope", md.getScope().identify()); } result.addContent(child); } } public static List<ModelRootDescriptor> loadModelRoots(Iterable<Element> modelRootElements, MacroHelper macroHelper) { List<ModelRootDescriptor> result = ListSequence.fromList(new ArrayList<ModelRootDescriptor>()); for (Element element : modelRootElements) { Memento m = new MementoImpl(); readMemento(m, element, macroHelper); String type = element.getAttributeValue("type"); if (type == null) { // This is debug code to find out cause of https://youtrack.jetbrains.com/issue/MPS-22589. String msg = String.format("Unsupported model root detected in module at %s. Likely outdated module is being loaded, please check your environment", macroHelper.expandPath("${module}")); if (LOG.isEnabledFor(Level.ERROR)) { LOG.error(msg); } throw new IllegalStateException(msg); } ListSequence.fromList(result).addElement(new ModelRootDescriptor(type, m)); } return result; } public static List<ModuleFacetDescriptor> loadFacets(Iterable<Element> facetElements, MacroHelper macroHelper) { List<ModuleFacetDescriptor> result = ListSequence.fromList(new ArrayList<ModuleFacetDescriptor>()); for (Element element : facetElements) { Memento m = new MementoImpl(); readMemento(m, element, macroHelper); String type = element.getAttributeValue("type"); if (type != null) { ListSequence.fromList(result).addElement(new ModuleFacetDescriptor(type, m)); } } return result; } public static void readMemento(Memento memento, Element element, final MacroHelper macroHelper) { for (Attribute attr : (List<Attribute>) element.getAttributes()) { String name = attr.getName(); memento.put(name, (isPathAttribute(name) ? macroHelper.expandPath(attr.getValue()) : attr.getValue())); } for (Element elem : (List<Element>) element.getChildren()) { Memento child = memento.createChild(elem.getName()); readMemento(child, elem, macroHelper); } } public static void writeMemento(Memento memento, Element element, final MacroHelper macroHelper) { for (String key : memento.getKeys()) { element.setAttribute(key, (isPathAttribute(key) ? macroHelper.shrinkPath(memento.get(key)) : memento.get(key))); } for (Memento childMemento : memento.getChildren()) { Element child = new Element(childMemento.getType()); writeMemento(childMemento, child, macroHelper); element.addContent(child); } } private static boolean isPathAttribute(String name) { return name.equals("path") || name.endsWith("Path"); } public static List<String> loadStubModelEntries(Element stubModelEntriesElement, final MacroHelper macroHelper) { return Sequence.fromIterable(XmlUtil.children(stubModelEntriesElement, "stubModelEntry")).select(new ISelector<Element, String>() { public String select(Element mre) { return loadStubModelEntry(mre, macroHelper); } }).where(new IWhereFilter<String>() { public boolean accept(String it) { return it != null; } }).toListSequence(); } private static String loadStubModelEntry(Element modelRootElement, MacroHelper macroHelper) { Element manager = XmlUtil.first(modelRootElement, "manager"); if (manager != null) { String className = XmlUtil.stringWithDefault(manager, "className", ""); if (!("jetbrains.mps.baseLanguage.stubs.JavaStubs".equals(className))) { return null; } } return macroHelper.expandPath(modelRootElement.getAttributeValue("path")); } public static void saveFacets(Element result, Collection<ModuleFacetDescriptor> facets, MacroHelper macroHelper) { for (ModuleFacetDescriptor facet : CollectionSequence.fromCollection(facets)) { Memento memento = facet.getMemento(); Element facetElement = new Element("facet"); writeMemento(memento, facetElement, macroHelper); String type = facet.getType(); facetElement.setAttribute("type", type); result.addContent(facetElement); } } public static void saveModelRoots(Element result, Collection<ModelRootDescriptor> modelRoots, MacroHelper macroHelper) { for (ModelRootDescriptor root : CollectionSequence.fromCollection(modelRoots)) { Memento memento = root.getMemento(); Element modelRoot = new Element("modelRoot"); writeMemento(memento, modelRoot, macroHelper); String type = root.getType(); if ((type != null && type.length() > 0) && !("obsolete".equals(type))) { modelRoot.setAttribute("type", type); } else { modelRoot.removeAttribute("type"); } result.addContent(modelRoot); } } public static void saveStubModelEntries(Element result, Collection<String> entries, MacroHelper macroHelper) { for (String root : entries) { Element stubModelEntry = new Element("stubModelEntry"); stubModelEntry.setAttribute("path", macroHelper.shrinkPath((root == null ? "" : root))); result.addContent(stubModelEntry); } } public static void setTimestamp(ModuleDescriptor descriptor, IFile file) { descriptor.setTimestamp(Long.toString(file.lastModified())); } public static void loadBrokenModule(ModuleDescriptor md, IFile file, ModuleReadException exception) { if (LOG.isEnabledFor(Level.WARN)) { LOG.warn("Module descriptor " + md + " from the file " + file + " has been loaded with error " + exception); } md.setNamespace(FileUtil.getNameWithoutExtension(file.getName())); md.setId(ModuleId.regular()); InputStreamReader r = null; try { r = new InputStreamReader(file.openInputStream(), FileUtil.DEFAULT_CHARSET); char[] buf = new char[1024]; int readChars = r.read(buf); if (readChars >= 0) { String s = new String(buf, 0, readChars); Pattern pattern = Pattern.compile(HEADER_PATTERN); for (String line : s.split("\n")) { Matcher m = pattern.matcher(line); if (m.matches()) { md.setNamespace(m.group(3)); md.setId(ModuleId.fromString(m.group(4))); } } } } catch (IOException e) { if (LOG.isEnabledFor(Level.ERROR)) { LOG.error("", e); } } finally { FileUtil.closeFileSafe(r); } setTimestamp(md, file); md.setLoadException((exception.getCause() == null ? exception : exception.getCause())); } }