public static void saveLanguageDescriptor(
      IFile file, LanguageDescriptor descriptor, MacroHelper macroHelper) {
    if (file.isReadOnly()) {
      if (LOG.isEnabledFor(Priority.ERROR)) {
        LOG.error("Cant't save " + file.getPath());
      }
      return;
    }

    Element languageElement = new Element("language");
    languageElement.setAttribute("namespace", descriptor.getNamespace());
    String uuid = descriptor.getUUID();
    if (uuid != null) {
      languageElement.setAttribute("uuid", uuid);
    }
    if (descriptor.getGenPath() != null) {
      languageElement.setAttribute(
          "generatorOutputPath", macroHelper.shrinkPath(descriptor.getGenPath()));
    }

    Element models = new Element("models");
    ModuleDescriptorPersistence.saveModelRoots(
        models, descriptor.getModelRootDescriptors(), macroHelper);
    languageElement.addContent(models);

    if (!(descriptor.getModuleFacetDescriptors().isEmpty())) {
      Element facets = new Element("facets");
      ModuleDescriptorPersistence.saveFacets(
          facets, descriptor.getModuleFacetDescriptors(), macroHelper);
      languageElement.addContent(facets);
    }

    Element accessoryModels = new Element("accessoryModels");
    for (SModelReference model : SetSequence.fromSet(descriptor.getAccessoryModels())) {
      XmlUtil.tagWithAttribute(accessoryModels, "model", "modelUID", model.toString());
    }
    languageElement.addContent(accessoryModels);

    Element generators = new Element("generators");
    for (GeneratorDescriptor generatorDescriptor :
        ListSequence.fromList(descriptor.getGenerators())) {
      GeneratorDescriptorPersistence.saveGeneratorDescriptor(
          generators, generatorDescriptor, macroHelper);
    }
    languageElement.addContent(generators);

    if (!(descriptor.getAdditionalJavaStubPaths().isEmpty())) {
      Element stubModelEntries = new Element("stubModelEntries");
      ModuleDescriptorPersistence.saveStubModelEntries(
          stubModelEntries, descriptor.getAdditionalJavaStubPaths(), macroHelper);
      languageElement.addContent(stubModelEntries);
    }

    Element sourcePath = new Element("sourcePath");
    for (String p : descriptor.getSourcePaths()) {
      XmlUtil.tagWithAttribute(sourcePath, "source", "path", macroHelper.shrinkPath(p));
    }
    languageElement.addContent(sourcePath);

    ModuleDescriptorPersistence.saveDependencies(languageElement, descriptor);

    Element extendedLanguages = new Element("extendedLanguages");
    for (SModuleReference ref : SetSequence.fromSet(descriptor.getExtendedLanguages())) {
      XmlUtil.tagWithText(extendedLanguages, "extendedLanguage", ref.toString());
    }
    languageElement.addContent(extendedLanguages);

    try {
      OutputStream os = file.openOutputStream();
      JDOMUtil.writeDocument(new Document(languageElement), os);
    } catch (Exception e) {
      if (LOG.isEnabledFor(Priority.ERROR)) {
        LOG.error("", e);
      }
    }
    ModuleDescriptorPersistence.setTimestamp(descriptor, file);
  }
  public static void saveGeneratorDescriptor(
      Element languageGeneratorsElement, GeneratorDescriptor descriptor, MacroHelper macroHelper) {
    Element generator = new Element("generator");
    if (descriptor.getNamespace() != null) {
      generator.setAttribute("name", descriptor.getNamespace());
    }
    if (descriptor.getGeneratorUID() != null) {
      generator.setAttribute("generatorUID", descriptor.getGeneratorUID());
    }
    if (descriptor.getUUID() != null) {
      generator.setAttribute("uuid", descriptor.getUUID());
    }
    if (descriptor.isGenerateTemplates()) {
      generator.setAttribute(
          "generate-templates", Boolean.toString(descriptor.isGenerateTemplates()));
    }
    if (!(descriptor.isReflectiveQueries())) {
      generator.setAttribute("reflective-queries", Boolean.toString(false));
    }
    if (!(descriptor.needsOperationContext())) {
      generator.setAttribute("needs-opctx", Boolean.toString(false));
    }

    Element models = new Element("models");
    ModuleDescriptorPersistence.saveModelRoots(
        models, descriptor.getModelRootDescriptors(), macroHelper);
    generator.addContent(models);

    if (!(descriptor.getModuleFacetDescriptors().isEmpty())) {
      Element facets = new Element("facets");
      ModuleDescriptorPersistence.saveFacets(
          facets, descriptor.getModuleFacetDescriptors(), macroHelper);
      generator.addContent(facets);
    }

    // "depends on" generators
    Element extTemplates = new Element("external-templates");
    for (SModuleReference generatorReference : SetSequence.fromSet(descriptor.getDepGenerators())) {
      XmlUtil.tagWithAttribute(
          extTemplates, "generator", "generatorUID", generatorReference.toString());
    }
    generator.addContent(extTemplates);

    ModuleDescriptorPersistence.saveDependencies(generator, descriptor);

    // mapping priority rules
    Element mapPrio = new Element("mapping-priorities");
    for (MappingPriorityRule rule : ListSequence.fromList(descriptor.getPriorityRules())) {
      Element ruleElement = new Element("mapping-priority-rule");
      ruleElement.setAttribute("kind", rule.getType().getName());

      Element gpm = new Element("greater-priority-mapping");
      saveGeneratorMappingConfigRef(rule.getLeft(), gpm);
      ruleElement.addContent(gpm);

      Element lpm = new Element("lesser-priority-mapping");
      saveGeneratorMappingConfigRef(rule.getRight(), lpm);
      ruleElement.addContent(lpm);

      mapPrio.addContent(ruleElement);
    }
    generator.addContent(mapPrio);

    languageGeneratorsElement.addContent(generator);
  }