new project model: saving artifacts configuration to xml
authornik <Nikolay.Chashnikov@jetbrains.com>
Mon, 6 Aug 2012 13:37:14 +0000 (17:37 +0400)
committernik <Nikolay.Chashnikov@jetbrains.com>
Tue, 7 Aug 2012 05:14:26 +0000 (09:14 +0400)
17 files changed:
jps/model-api/src/org/jetbrains/jps/model/artifact/JpsArtifact.java
jps/model-impl/src/org/jetbrains/jps/model/artifact/impl/JpsArtifactImpl.java
jps/model-impl/src/org/jetbrains/jps/model/impl/JpsNamedElementReferenceBase.java
jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsLibraryTableSerializer.java
jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModelSerializerExtension.java
jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModuleSerializer.java
jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java
jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactLoader.java [deleted file]
jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactSerializer.java [new file with mode: 0644]
jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactTypeSerializer.java [new file with mode: 0644]
jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsPackagingElementLoader.java [deleted file]
jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsPackagingElementSerializer.java [new file with mode: 0644]
jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/JpsJavaModelSerializerExtension.java
jps/model-serialization/testData/sampleProject/.idea/artifacts/dir.xml [new file with mode: 0644]
jps/model-serialization/testData/sampleProject/.idea/artifacts/jar.xml [new file with mode: 0644]
jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsArtifactSerializationTest.java [new file with mode: 0644]
jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsProjectSerializationTest.java

index 0fbf491a99d390e2da7d0bed366e7dcb9dd75d99..7a4526b555eb1f118d9d18596cd0e1b9f1342eee 100644 (file)
@@ -24,7 +24,11 @@ public interface JpsArtifact extends JpsNamedElement, JpsReferenceableElement<Jp
 
   void setRootElement(@NotNull JpsCompositePackagingElement rootElement);
 
+  boolean isBuildOnMake();
+
   @NotNull
   @Override
   JpsArtifactReference createReference();
+
+  void setBuildOnMake(boolean buildOnMake);
 }
index 8298e3dbb7ddf93f51a7d2644f2a5bb854573120..cf1708f39b2bb180a962a2eab65a6ff153579d31 100644 (file)
@@ -21,6 +21,8 @@ public class JpsArtifactImpl extends JpsNamedCompositeElementBase<JpsArtifactImp
     ROOT_ELEMENT_CHILD_ROLE = JpsElementChildRoleBase.create("root element");
   private static final JpsTypedDataRole<JpsArtifactType> TYPED_DATA_ROLE = new JpsTypedDataRole<JpsArtifactType>();
   private String myOutputPath;
+  private boolean myBuildOnMake;
+
 
   public JpsArtifactImpl(@NotNull String name, @NotNull JpsCompositePackagingElement rootElement, @NotNull JpsArtifactType type) {
     super(name);
@@ -72,4 +74,17 @@ public class JpsArtifactImpl extends JpsNamedCompositeElementBase<JpsArtifactImp
   public void setRootElement(@NotNull JpsCompositePackagingElement rootElement) {
     myContainer.setChild(ROOT_ELEMENT_CHILD_ROLE, rootElement);
   }
+
+  @Override
+  public boolean isBuildOnMake() {
+    return myBuildOnMake;
+  }
+
+  @Override
+  public void setBuildOnMake(boolean buildOnMake) {
+    if (myBuildOnMake != buildOnMake) {
+      myBuildOnMake = buildOnMake;
+      fireElementChanged();
+    }
+  }
 }
index b3e79b1364b5415e8188026d3454b47c5a2ad1c0..b539125bc7a93e831b09314f73d6a9299757c3e0 100644 (file)
@@ -11,7 +11,7 @@ import java.util.List;
 public abstract class JpsNamedElementReferenceBase<T extends JpsNamedElement, Self extends JpsNamedElementReferenceBase<T, Self>>
   extends JpsCompositeElementBase<Self> implements JpsElementReference<T> {
   private static final JpsElementChildRole<JpsElementReference<? extends JpsCompositeElement>> PARENT_REFERENCE_ROLE = JpsElementChildRoleBase.create("parent");
-  private final JpsElementCollectionRole<? extends T> myCollectionRole;
+  protected final JpsElementCollectionRole<? extends T> myCollectionRole;
   protected final String myElementName;
 
   protected JpsNamedElementReferenceBase(@NotNull JpsElementCollectionRole<? extends T> role,
index a16a04fc3f170d67db8f4d59db2834b98e51a8b6..d818964503e5a7eab3f380b99bfc4e2f32ab4b64 100644 (file)
@@ -5,11 +5,10 @@ import com.intellij.util.containers.MultiMap;
 import org.jdom.Element;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
-import org.jetbrains.jps.model.DummyJpsElementProperties;
-import org.jetbrains.jps.model.JpsElementFactory;
-import org.jetbrains.jps.model.JpsElementProperties;
+import org.jetbrains.jps.model.*;
 import org.jetbrains.jps.model.java.JpsJavaLibraryType;
 import org.jetbrains.jps.model.library.*;
+import org.jetbrains.jps.model.module.JpsModuleReference;
 
 import java.util.*;
 
@@ -40,6 +39,9 @@ public class JpsLibraryTableSerializer {
       public void saveProperties(DummyJpsElementProperties properties, Element element) {
       }
     };
+  private static final String MODULE_LEVEL = "module";
+  private static final String PROJECT_LEVEL = "project";
+  private static final String APPLICATION_LEVEL = "application";
 
   public static void loadLibraries(Element libraryTableElement, JpsLibraryCollection result) {
     for (Element libraryElement : JDOMUtil.getChildren(libraryTableElement, LIBRARY_TAG)) {
@@ -207,4 +209,41 @@ public class JpsLibraryTableSerializer {
     }
     throw new IllegalArgumentException("unknown type library:" + type);
   }
+
+  public static JpsElementReference<? extends JpsCompositeElement> createLibraryTableReference(String level) {
+    JpsElementFactory elementFactory = JpsElementFactory.getInstance();
+    if (level.equals(PROJECT_LEVEL)) {
+      return elementFactory.createProjectReference();
+    }
+    if (level.equals(APPLICATION_LEVEL)) {
+      return elementFactory.createGlobalReference();
+    }
+    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
+      final JpsElementReference<? extends JpsCompositeElement> reference = extension.createLibraryTableReference(level);
+      if (reference != null) {
+        return reference;
+      }
+    }
+    throw new UnsupportedOperationException();
+  }
+
+  public static String getLevelId(JpsElementReference<? extends JpsCompositeElement> reference) {
+    if (reference instanceof JpsModuleReference) {
+      return MODULE_LEVEL;
+    }
+    JpsCompositeElement element = reference.resolve();
+    if (element instanceof JpsProject) {
+      return PROJECT_LEVEL;
+    }
+    else if (element instanceof JpsGlobal) {
+      return APPLICATION_LEVEL;
+    }
+    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
+      String levelId = extension.getLibraryTableLevelId(reference);
+      if (levelId != null) {
+        return levelId;
+      }
+    }
+    return null;
+  }
 }
index 554fbb53449a0919eb183f532336959c9636cca7..3ef2636b0ca32656da3d69a98368710fff577915 100644 (file)
@@ -6,10 +6,10 @@ import org.jetbrains.annotations.Nullable;
 import org.jetbrains.jps.model.JpsCompositeElement;
 import org.jetbrains.jps.model.JpsElementReference;
 import org.jetbrains.jps.model.JpsProject;
-import org.jetbrains.jps.model.artifact.JpsArtifactType;
 import org.jetbrains.jps.model.module.JpsDependencyElement;
 import org.jetbrains.jps.model.module.JpsModule;
-import org.jetbrains.jps.model.serialization.artifact.JpsPackagingElementLoader;
+import org.jetbrains.jps.model.serialization.artifact.JpsArtifactTypeSerializer;
+import org.jetbrains.jps.model.serialization.artifact.JpsPackagingElementSerializer;
 import org.jetbrains.jps.model.serialization.facet.JpsModuleExtensionLoader;
 import org.jetbrains.jps.service.JpsServiceManager;
 
@@ -79,12 +79,11 @@ public abstract class JpsModelSerializerExtension {
     return Collections.emptyList();
   }
 
-  public List<? extends JpsPackagingElementLoader<?>> getPackagingElementLoaders() {
+  public List<? extends JpsPackagingElementSerializer<?>> getPackagingElementSerializers() {
     return Collections.emptyList();
   }
 
-  @Nullable
-  public JpsArtifactType getArtifactType(@NotNull String typeId) {
-    return null;
+  public List<JpsArtifactTypeSerializer> getArtifactTypeSerializers() {
+    return Collections.emptyList();
   }
 }
index 5072f99e9d78f411ae0c607c5d4825c49b995e46..eb33ef7b6ba00a6a54fc2f427d59bbdd87e84934 100644 (file)
@@ -42,8 +42,6 @@ public class JpsModuleSerializer {
   private static final String MODULE_LIBRARY_TYPE = "module-library";
   private static final String MODULE_TYPE = "module";
   private static final String MODULE_NAME_ATTRIBUTE = "module-name";
-  private static final String PROJECT_LEVEL = "project";
-  private static final String APPLICATION_LEVEL = "application";
   private static final String GENERATED_LIBRARY_NAME_PREFIX = "#";
 
   public static void loadRootModel(JpsModule module, Element rootModelComponent, JpsSdkType<?> projectSdkType) {
@@ -84,7 +82,8 @@ public class JpsModuleSerializer {
         String name = orderEntry.getAttributeValue(NAME_ATTRIBUTE);
         String level = orderEntry.getAttributeValue(LEVEL_ATTRIBUTE);
         final JpsLibraryDependency dependency =
-          dependenciesList.addLibraryDependency(elementFactory.createLibraryReference(name, createLibraryTableReference(level)));
+          dependenciesList.addLibraryDependency(elementFactory.createLibraryReference(name, JpsLibraryTableSerializer
+            .createLibraryTableReference(level)));
         loadModuleDependencyProperties(dependency, orderEntry);
       }
       else if (MODULE_LIBRARY_TYPE.equals(type)) {
@@ -170,14 +169,14 @@ public class JpsModuleSerializer {
           JpsLibrary library = reference.resolve();
           String libraryName = library.getName();
           JpsLibraryTableSerializer
-            .saveLibrary(library, libraryElement, libraryName.startsWith(GENERATED_LIBRARY_NAME_PREFIX) ? null : libraryName);
+            .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, getLevelId(parentReference));
+          element.setAttribute(LEVEL_ATTRIBUTE, JpsLibraryTableSerializer.getLevelId(parentReference));
         }
         rootModelElement.addContent(element);
       }
@@ -194,6 +193,10 @@ public class JpsModuleSerializer {
     }
   }
 
+  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);
   }
@@ -215,38 +218,4 @@ public class JpsModuleSerializer {
       extension.saveModuleDependencyProperties(dependency, orderEntry);
     }
   }
-
-  public static JpsElementReference<? extends JpsCompositeElement> createLibraryTableReference(String level) {
-    JpsElementFactory elementFactory = JpsElementFactory.getInstance();
-    if (level.equals(PROJECT_LEVEL)) {
-      return elementFactory.createProjectReference();
-    }
-    if (level.equals(APPLICATION_LEVEL)) {
-      return elementFactory.createGlobalReference();
-    }
-    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
-      final JpsElementReference<? extends JpsCompositeElement> reference = extension.createLibraryTableReference(level);
-      if (reference != null) {
-        return reference;
-      }
-    }
-    throw new UnsupportedOperationException();
-  }
-
-  private static String getLevelId(JpsElementReference<? extends JpsCompositeElement> reference) {
-    JpsCompositeElement element = reference.resolve();
-    if (element instanceof JpsProject) {
-      return PROJECT_LEVEL;
-    }
-    else if (element instanceof JpsGlobal) {
-      return APPLICATION_LEVEL;
-    }
-    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
-      String levelId = extension.getLibraryTableLevelId(reference);
-      if (levelId != null) {
-        return levelId;
-      }
-    }
-    return null;
-  }
 }
index cffd93202c47016aca6fefe5c58a06c7397aea9b..c1ff0b78b29574cc67aff2df936711e40e367535 100644 (file)
@@ -13,7 +13,7 @@ import org.jetbrains.jps.model.JpsProject;
 import org.jetbrains.jps.model.java.JpsJavaModuleType;
 import org.jetbrains.jps.model.library.JpsSdkType;
 import org.jetbrains.jps.model.module.JpsModule;
-import org.jetbrains.jps.model.serialization.artifact.JpsArtifactLoader;
+import org.jetbrains.jps.model.serialization.artifact.JpsArtifactSerializer;
 import org.jetbrains.jps.model.serialization.facet.JpsFacetLoader;
 
 import java.io.File;
@@ -98,7 +98,7 @@ public class JpsProjectLoader extends JpsLoaderBase {
   }
 
   private void loadArtifacts(Element artifactManagerComponent) {
-    JpsArtifactLoader.loadArtifacts(myProject, artifactManagerComponent);
+    JpsArtifactSerializer.loadArtifacts(myProject, artifactManagerComponent);
   }
 
   @Nullable
diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactLoader.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactLoader.java
deleted file mode 100644 (file)
index e8e117a..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-package org.jetbrains.jps.model.serialization.artifact;
-
-import com.intellij.openapi.util.JDOMUtil;
-import com.intellij.util.xmlb.XmlSerializer;
-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.JpsElementFactory;
-import org.jetbrains.jps.model.JpsElementReference;
-import org.jetbrains.jps.model.JpsProject;
-import org.jetbrains.jps.model.artifact.*;
-import org.jetbrains.jps.model.artifact.elements.JpsCompositePackagingElement;
-import org.jetbrains.jps.model.artifact.elements.JpsPackagingElement;
-import org.jetbrains.jps.model.artifact.elements.JpsPackagingElementFactory;
-import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension;
-import org.jetbrains.jps.model.serialization.JpsModuleSerializer;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * @author nik
- */
-public class JpsArtifactLoader {
-  private static List<? extends JpsPackagingElementLoader<?>> STANDARD_LOADERS = Arrays.asList();
-  
-  public static void loadArtifacts(@NotNull JpsProject project, @Nullable Element componentElement) {
-    JpsArtifactService service = JpsArtifactService.getInstance();
-    for (Element artifactElement : JDOMUtil.getChildren(componentElement, "artifact")) {
-      ArtifactState state = XmlSerializer.deserialize(artifactElement, ArtifactState.class);
-      if (state == null) continue;
-      JpsArtifactType artifactType = getArtifactType(state.getArtifactType());
-      JpsPackagingElement rootElement = loadPackagingElement(state.getRootElement());
-      if (rootElement != null) {
-        JpsArtifact artifact = service.addArtifact(project, state.getName(), (JpsCompositePackagingElement)rootElement, artifactType);
-        artifact.setOutputPath(state.getOutputPath());
-      }
-    }
-  }
-
-  @Nullable
-  private static JpsPackagingElement loadPackagingElement(Element element) {
-    JpsPackagingElement packagingElement = createPackagingElement(element);
-    if (packagingElement instanceof JpsCompositePackagingElement) {
-      for (Element childElement : JDOMUtil.getChildren(element, "element")) {
-        JpsPackagingElement child = loadPackagingElement(childElement);
-        if (child != null) {
-          ((JpsCompositePackagingElement)packagingElement).addChild(child);
-        }
-      }
-    }
-    return packagingElement;
-  }
-
-  @Nullable
-  private static JpsPackagingElement createPackagingElement(Element element) {
-    String typeId = element.getAttributeValue("id");
-    JpsPackagingElementFactory factory = JpsPackagingElementFactory.getInstance();
-    if (typeId.equals("root")) {
-      return factory.createArtifactRoot();
-    }
-    if (typeId.equals("directory")) {
-      return factory.createDirectory(element.getAttributeValue("name"));
-    }
-    if (typeId.equals("archive")) {
-      return factory.createArchive(element.getAttributeValue("name"));
-    }
-    if (typeId.equals("file-copy")) {
-      return factory.createFileCopy(element.getAttributeValue("path"),
-                                     element.getAttributeValue("output-file-name"));
-    }
-    if (typeId.equals("dir-copy")) {
-      return factory.createDirectoryCopy(element.getAttributeValue("path"));
-    }
-    if (typeId.equals("extracted-dir")) {
-      return factory.createExtractedDirectory(element.getAttributeValue("path"),
-                                               element.getAttributeValue("path-in-jar"));
-    }
-    if (typeId.equals("library")) {
-      String level = element.getAttributeValue("level");
-      String libraryName = element.getAttributeValue("name");
-      String moduleName = element.getAttributeValue("module-name");
-      JpsElementReference<? extends JpsCompositeElement> parentReference;
-      if (moduleName != null) {
-        parentReference = JpsElementFactory.getInstance().createModuleReference(moduleName);
-      }
-      else {
-        parentReference = JpsModuleSerializer.createLibraryTableReference(level);
-      }
-      return factory.createLibraryElement(JpsElementFactory.getInstance().createLibraryReference(libraryName, parentReference));
-    }
-    if (typeId.equals("artifact")) {
-      return factory.createArtifactOutput(JpsArtifactService.getInstance().createReference(element.getAttributeValue("artifact-name")));
-    }
-    JpsPackagingElementLoader<?> loader = findElementLoader(typeId);
-    if (loader != null) {
-      return loader.load(element);
-    }
-    return null;
-  }
-
-  private static JpsArtifactType getArtifactType(@Nullable String typeId) {
-    if (typeId == null || "plain".equals(typeId)) {
-      return DirectoryArtifactType.INSTANCE;
-    }
-    if (typeId.equals("jar")) {
-      return JarArtifactType.INSTANCE;
-    }
-    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
-      JpsArtifactType type = extension.getArtifactType(typeId);
-      if (type != null) {
-        return type;
-      }
-    }
-    return DirectoryArtifactType.INSTANCE;
-  }
-
-  @Nullable 
-  private static JpsPackagingElementLoader<?> findElementLoader(@NotNull String typeId) {
-    for (JpsPackagingElementLoader<?> loader : STANDARD_LOADERS) {
-      if (loader.getTypeId().equals(typeId)) {
-        return loader;
-      }
-    }
-    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
-      for (JpsPackagingElementLoader<?> loader : extension.getPackagingElementLoaders()) {
-        if (loader.getTypeId().equals(typeId)) {
-          return loader;
-        }
-      }
-    }
-    return null;
-  }
-}
diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactSerializer.java
new file mode 100644 (file)
index 0000000..02d23da
--- /dev/null
@@ -0,0 +1,325 @@
+package org.jetbrains.jps.model.serialization.artifact;
+
+import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
+import com.intellij.util.xmlb.XmlSerializer;
+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.JpsElementFactory;
+import org.jetbrains.jps.model.JpsElementReference;
+import org.jetbrains.jps.model.JpsProject;
+import org.jetbrains.jps.model.artifact.*;
+import org.jetbrains.jps.model.artifact.elements.*;
+import org.jetbrains.jps.model.library.JpsLibraryReference;
+import org.jetbrains.jps.model.module.JpsModuleReference;
+import org.jetbrains.jps.model.serialization.JpsLibraryTableSerializer;
+import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension;
+
+/**
+ * @author nik
+ */
+public class JpsArtifactSerializer {
+  private static JpsPackagingElementSerializer<?>[] STANDARD_SERIALIZERS = {
+    new ArtifactRootElementSerializer(),
+    new DirectoryElementSerializer(),
+    new ArchiveElementSerializer(),
+    new FileCopyElementSerializer(),
+    new DirectoryCopyElementSerializer(),
+    new ExtractedDirectoryElementSerializer(),
+    new LibraryFilesElementSerializer(),
+    new ArtifactOutputElementSerializer()
+  };
+  private static final JpsArtifactTypeSerializer[] STANDARD_TYPE_SERIALIZERS = {
+    new JpsArtifactTypeSerializer("plain", DirectoryArtifactType.INSTANCE),
+    new JpsArtifactTypeSerializer("jar", JarArtifactType.INSTANCE)
+  };
+  private static final String ELEMENT_TAG = "element";
+  private static final String ID_ATTRIBUTE = "id";
+  private static final SkipDefaultValuesSerializationFilters SERIALIZATION_FILTERS = new SkipDefaultValuesSerializationFilters();
+
+
+  public static void loadArtifacts(@NotNull JpsProject project, @Nullable Element componentElement) {
+    JpsArtifactService service = JpsArtifactService.getInstance();
+    for (Element artifactElement : JDOMUtil.getChildren(componentElement, "artifact")) {
+      ArtifactState state = XmlSerializer.deserialize(artifactElement, ArtifactState.class);
+      if (state == null) continue;
+      JpsArtifactType artifactType = getTypeSerializer(state.getArtifactType()).getType();
+      JpsPackagingElement rootElement = loadPackagingElement(state.getRootElement());
+      if (rootElement != null) {
+        JpsArtifact artifact = service.addArtifact(project, state.getName(), (JpsCompositePackagingElement)rootElement, artifactType);
+        artifact.setBuildOnMake(state.isBuildOnMake());
+        artifact.setOutputPath(state.getOutputPath());
+      }
+    }
+  }
+
+  public static void saveArtifact(@NotNull JpsArtifact artifact, Element componentElement) {
+    ArtifactState state = new ArtifactState();
+    state.setName(artifact.getName());
+    state.setBuildOnMake(artifact.isBuildOnMake());
+    state.setOutputPath(artifact.getOutputPath());
+    state.setArtifactType(getTypeSerializer(artifact.getArtifactType()).getTypeId());
+    state.setRootElement(savePackagingElement(artifact.getRootElement()));
+    componentElement.addContent(XmlSerializer.serialize(state, SERIALIZATION_FILTERS));
+  }
+
+  private static <P extends JpsPackagingElement> Element savePackagingElement(P element) {
+    //noinspection unchecked
+    JpsPackagingElementSerializer<P> serializer = findElementSerializer((Class<P>)element.getClass());
+    Element tag = new Element(ELEMENT_TAG).setAttribute(ID_ATTRIBUTE, serializer.getTypeId());
+    serializer.save(element, tag);
+    if (element instanceof JpsCompositePackagingElement) {
+      for (JpsPackagingElement child : ((JpsCompositePackagingElement)element).getChildren()) {
+        tag.addContent(savePackagingElement(child));
+      }
+    }
+    return tag;
+  }
+
+  @Nullable
+  private static JpsPackagingElement loadPackagingElement(Element element) {
+    JpsPackagingElement packagingElement = createPackagingElement(element);
+    if (packagingElement instanceof JpsCompositePackagingElement) {
+      for (Element childElement : JDOMUtil.getChildren(element, ELEMENT_TAG)) {
+        JpsPackagingElement child = loadPackagingElement(childElement);
+        if (child != null) {
+          ((JpsCompositePackagingElement)packagingElement).addChild(child);
+        }
+      }
+    }
+    return packagingElement;
+  }
+
+  @Nullable
+  private static JpsPackagingElement createPackagingElement(Element element) {
+    String typeId = element.getAttributeValue(ID_ATTRIBUTE);
+    JpsPackagingElementSerializer<?> serializer = findElementSerializer(typeId);
+    if (serializer != null) {
+      return serializer.load(element);
+    }
+    return null;
+  }
+
+  @Nullable 
+  private static JpsPackagingElementSerializer<?> findElementSerializer(@NotNull String typeId) {
+    for (JpsPackagingElementSerializer<?> serializer : STANDARD_SERIALIZERS) {
+      if (serializer.getTypeId().equals(typeId)) {
+        return serializer;
+      }
+    }
+    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
+      for (JpsPackagingElementSerializer<?> serializer : extension.getPackagingElementSerializers()) {
+        if (serializer.getTypeId().equals(typeId)) {
+          return serializer;
+        }
+      }
+    }
+    return null;
+  }
+
+  @NotNull
+  private static <E extends JpsPackagingElement> JpsPackagingElementSerializer<E> findElementSerializer(@NotNull Class<E> elementClass) {
+    for (JpsPackagingElementSerializer<?> serializer : STANDARD_SERIALIZERS) {
+      if (serializer.getElementClass().isAssignableFrom(elementClass)) {
+        //noinspection unchecked
+        return (JpsPackagingElementSerializer<E>)serializer;
+      }
+    }
+    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
+      for (JpsPackagingElementSerializer<?> serializer : extension.getPackagingElementSerializers()) {
+        if (serializer.getElementClass().isAssignableFrom(elementClass)) {
+          //noinspection unchecked
+          return (JpsPackagingElementSerializer<E>)serializer;
+        }
+      }
+    }
+    throw new IllegalArgumentException("Serializer not found for " + elementClass);
+  }
+
+  private static JpsArtifactTypeSerializer getTypeSerializer(String typeId) {
+    for (JpsArtifactTypeSerializer serializer : STANDARD_TYPE_SERIALIZERS) {
+      if (serializer.getTypeId().equals(typeId)) {
+        return serializer;
+      }
+    }
+    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
+      for (JpsArtifactTypeSerializer serializer : extension.getArtifactTypeSerializers()) {
+        if (serializer.getTypeId().equals(typeId)) {
+          return serializer;
+        }
+      }
+    }
+    return null;
+  }
+
+  private static JpsArtifactTypeSerializer getTypeSerializer(JpsArtifactType type) {
+    for (JpsArtifactTypeSerializer serializer : STANDARD_TYPE_SERIALIZERS) {
+      if (serializer.getType().equals(type)) {
+        return serializer;
+      }
+    }
+    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
+      for (JpsArtifactTypeSerializer serializer : extension.getArtifactTypeSerializers()) {
+        if (serializer.getType().equals(type)) {
+          return serializer;
+        }
+      }
+    }
+    return null;
+  }
+
+  private static class ArtifactRootElementSerializer extends JpsPackagingElementSerializer<JpsArtifactRootElement> {
+    public ArtifactRootElementSerializer() {
+      super("root", JpsArtifactRootElement.class);
+    }
+
+    @Override
+    public JpsArtifactRootElement load(Element element) {
+      return JpsPackagingElementFactory.getInstance().createArtifactRoot();
+    }
+
+    @Override
+    public void save(JpsArtifactRootElement element, Element tag) {
+    }
+  }
+
+  private static class DirectoryElementSerializer extends JpsPackagingElementSerializer<JpsDirectoryPackagingElement> {
+    public DirectoryElementSerializer() {
+      super("directory", JpsDirectoryPackagingElement.class);
+    }
+
+    @Override
+    public JpsDirectoryPackagingElement load(Element element) {
+      return JpsPackagingElementFactory.getInstance().createDirectory(element.getAttributeValue("name"));
+    }
+
+    @Override
+    public void save(JpsDirectoryPackagingElement element, Element tag) {
+      tag.setAttribute("name", element.getDirectoryName());
+    }
+  }
+
+  private static class ArchiveElementSerializer extends JpsPackagingElementSerializer<JpsArchivePackagingElement> {
+    public ArchiveElementSerializer() {
+      super("archive", JpsArchivePackagingElement.class);
+    }
+
+    @Override
+    public JpsArchivePackagingElement load(Element element) {
+      return JpsPackagingElementFactory.getInstance().createArchive(element.getAttributeValue("name"));
+    }
+
+    @Override
+    public void save(JpsArchivePackagingElement element, Element tag) {
+      tag.setAttribute("name", element.getArchiveName());
+    }
+  }
+
+  private static class FileCopyElementSerializer extends JpsPackagingElementSerializer<JpsFileCopyPackagingElement> {
+    public FileCopyElementSerializer() {
+      super("file-copy", JpsFileCopyPackagingElement.class);
+    }
+
+    @Override
+    public JpsFileCopyPackagingElement load(Element element) {
+      return JpsPackagingElementFactory.getInstance().createFileCopy(element.getAttributeValue("path"),
+                                                                     element.getAttributeValue("output-file-name"));
+    }
+
+    @Override
+    public void save(JpsFileCopyPackagingElement element, Element tag) {
+      tag.setAttribute("path", element.getFilePath());
+      String outputFileName = element.getRenamedOutputFileName();
+      if (outputFileName != null) {
+        tag.setAttribute("output-path-name", outputFileName);
+      }
+    }
+  }
+
+  private static class DirectoryCopyElementSerializer extends JpsPackagingElementSerializer<JpsDirectoryCopyPackagingElement> {
+    public DirectoryCopyElementSerializer() {
+      super("dir-copy", JpsDirectoryCopyPackagingElement.class);
+    }
+
+    @Override
+    public JpsDirectoryCopyPackagingElement load(Element element) {
+      return JpsPackagingElementFactory.getInstance().createDirectoryCopy(element.getAttributeValue("path"));
+    }
+
+    @Override
+    public void save(JpsDirectoryCopyPackagingElement element, Element tag) {
+      tag.setAttribute("path", element.getDirectoryPath());
+    }
+  }
+
+  private static class ExtractedDirectoryElementSerializer
+    extends JpsPackagingElementSerializer<JpsExtractedDirectoryPackagingElement> {
+    public ExtractedDirectoryElementSerializer() {
+      super("extracted-dir", JpsExtractedDirectoryPackagingElement.class);
+    }
+
+    @Override
+    public JpsExtractedDirectoryPackagingElement load(Element element) {
+      return JpsPackagingElementFactory.getInstance().createExtractedDirectory(element.getAttributeValue("path"),
+                                                                               element.getAttributeValue("path-in-jar"));
+    }
+
+    @Override
+    public void save(JpsExtractedDirectoryPackagingElement element, Element tag) {
+      tag.setAttribute("path", element.getFilePath());
+      tag.setAttribute("path-in-jar", element.getPathInJar());
+    }
+  }
+
+  private static class LibraryFilesElementSerializer extends JpsPackagingElementSerializer<JpsLibraryFilesPackagingElement> {
+    public LibraryFilesElementSerializer() {
+      super("library", JpsLibraryFilesPackagingElement.class);
+    }
+
+    @Override
+    public JpsLibraryFilesPackagingElement load(Element element) {
+      String level = element.getAttributeValue("level");
+      String libraryName = element.getAttributeValue("name");
+      String moduleName = element.getAttributeValue("module-name");
+      JpsElementReference<? extends JpsCompositeElement> parentReference;
+      if (moduleName != null) {
+        parentReference = JpsElementFactory.getInstance().createModuleReference(moduleName);
+      }
+      else {
+        parentReference = JpsLibraryTableSerializer.createLibraryTableReference(level);
+      }
+      return JpsPackagingElementFactory.getInstance()
+        .createLibraryElement(JpsElementFactory.getInstance().createLibraryReference(libraryName, parentReference));
+    }
+
+    @Override
+    public void save(JpsLibraryFilesPackagingElement element, Element tag) {
+      JpsLibraryReference reference = element.getLibraryReference();
+      JpsElementReference<? extends JpsCompositeElement> parentReference = reference.getParentReference();
+      tag.setAttribute("level", JpsLibraryTableSerializer.getLevelId(parentReference));
+      tag.setAttribute("name", reference.getLibraryName());
+      if (parentReference instanceof JpsModuleReference) {
+        tag.setAttribute("module-name", ((JpsModuleReference)parentReference).getModuleName());
+      }
+    }
+  }
+
+  private static class ArtifactOutputElementSerializer extends JpsPackagingElementSerializer<JpsArtifactOutputPackagingElement> {
+    public ArtifactOutputElementSerializer() {
+      super("artifact", JpsArtifactOutputPackagingElement.class);
+    }
+
+    @Override
+    public JpsArtifactOutputPackagingElement load(Element element) {
+      return JpsPackagingElementFactory.getInstance()
+        .createArtifactOutput(JpsArtifactService.getInstance().createReference(element.getAttributeValue("artifact-name")));
+    }
+
+    @Override
+    public void save(JpsArtifactOutputPackagingElement element, Element tag) {
+      tag.setAttribute("artifact-name", element.getArtifactReference().getArtifactName());
+    }
+  }
+}
diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactTypeSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsArtifactTypeSerializer.java
new file mode 100644 (file)
index 0000000..d694b86
--- /dev/null
@@ -0,0 +1,24 @@
+package org.jetbrains.jps.model.serialization.artifact;
+
+import org.jetbrains.jps.model.artifact.JpsArtifactType;
+
+/**
+ * @author nik
+ */
+public class JpsArtifactTypeSerializer {
+  private final String myTypeId;
+  private final JpsArtifactType myType;
+
+  public JpsArtifactTypeSerializer(String typeId, JpsArtifactType type) {
+    myTypeId = typeId;
+    myType = type;
+  }
+
+  public String getTypeId() {
+    return myTypeId;
+  }
+
+  public JpsArtifactType getType() {
+    return myType;
+  }
+}
diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsPackagingElementLoader.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsPackagingElementLoader.java
deleted file mode 100644 (file)
index 3aca2b9..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.jetbrains.jps.model.serialization.artifact;
-
-import org.jdom.Element;
-import org.jetbrains.jps.model.artifact.elements.JpsPackagingElement;
-
-/**
- * @author nik
- */
-public abstract class JpsPackagingElementLoader<E extends JpsPackagingElement> {
-  private final String myTypeId;
-
-  protected JpsPackagingElementLoader(String typeId) {
-    myTypeId = typeId;
-  }
-
-  public String getTypeId() {
-    return myTypeId;
-  }
-
-  public abstract E load(Element element);
-}
diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsPackagingElementSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/JpsPackagingElementSerializer.java
new file mode 100644 (file)
index 0000000..0969831
--- /dev/null
@@ -0,0 +1,29 @@
+package org.jetbrains.jps.model.serialization.artifact;
+
+import org.jdom.Element;
+import org.jetbrains.jps.model.artifact.elements.JpsPackagingElement;
+
+/**
+ * @author nik
+ */
+public abstract class JpsPackagingElementSerializer<E extends JpsPackagingElement> {
+  private final String myTypeId;
+  private final Class<? extends E> myElementClass;
+
+  protected JpsPackagingElementSerializer(String typeId, Class<? extends E> elementClass) {
+    myTypeId = typeId;
+    myElementClass = elementClass;
+  }
+
+  public String getTypeId() {
+    return myTypeId;
+  }
+
+  public Class<? extends E> getElementClass() {
+    return myElementClass;
+  }
+
+  public abstract E load(Element element);
+
+  public abstract void save(E element, Element tag);
+}
index a9255e6f348233a37a9eb0dc483bd7f0347a564e..56168d4f6289e17ccf929ae3fc69958ca8e48751 100644 (file)
@@ -13,7 +13,7 @@ import org.jetbrains.jps.model.module.JpsModule;
 import org.jetbrains.jps.model.module.JpsModuleReference;
 import org.jetbrains.jps.model.serialization.JpsLibraryRootTypeSerializer;
 import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension;
-import org.jetbrains.jps.model.serialization.artifact.JpsPackagingElementLoader;
+import org.jetbrains.jps.model.serialization.artifact.JpsPackagingElementSerializer;
 
 import java.util.Arrays;
 import java.util.List;
@@ -119,8 +119,8 @@ public class JpsJavaModelSerializerExtension extends JpsModelSerializerExtension
   }
 
   @Override
-  public List<? extends JpsPackagingElementLoader<?>> getPackagingElementLoaders() {
-    return Arrays.asList(new JpsModuleOutputPackagingElementLoader(), new JpsTestModuleOutputPackagingElementLoader());
+  public List<? extends JpsPackagingElementSerializer<?>> getPackagingElementSerializers() {
+    return Arrays.asList(new JpsModuleOutputPackagingElementSerializer(), new JpsTestModuleOutputPackagingElementSerializer());
   }
 
   private static void loadExplodedDirectoryExtension(JpsModule module, Element rootModelComponent) {
@@ -212,9 +212,10 @@ public class JpsJavaModelSerializerExtension extends JpsModelSerializerExtension
     return JpsJavaExtensionService.getInstance();
   }
 
-  private static class JpsModuleOutputPackagingElementLoader extends JpsPackagingElementLoader<JpsProductionModuleOutputPackagingElement> {
-    private JpsModuleOutputPackagingElementLoader() {
-      super("module-output");
+  private static class JpsModuleOutputPackagingElementSerializer
+    extends JpsPackagingElementSerializer<JpsProductionModuleOutputPackagingElement> {
+    private JpsModuleOutputPackagingElementSerializer() {
+      super("module-output", JpsProductionModuleOutputPackagingElement.class);
     }
 
     @Override
@@ -222,11 +223,16 @@ public class JpsJavaModelSerializerExtension extends JpsModelSerializerExtension
       JpsModuleReference reference = JpsElementFactory.getInstance().createModuleReference(element.getAttributeValue("name"));
       return getService().createProductionModuleOutput(reference);
     }
+
+    @Override
+    public void save(JpsProductionModuleOutputPackagingElement element, Element tag) {
+      tag.setAttribute("name", element.getModuleReference().getModuleName());
+    }
   }
 
-  private static class JpsTestModuleOutputPackagingElementLoader extends JpsPackagingElementLoader<JpsTestModuleOutputPackagingElement> {
-    private JpsTestModuleOutputPackagingElementLoader() {
-      super("module-test-output");
+  private static class JpsTestModuleOutputPackagingElementSerializer extends JpsPackagingElementSerializer<JpsTestModuleOutputPackagingElement> {
+    private JpsTestModuleOutputPackagingElementSerializer() {
+      super("module-test-output", JpsTestModuleOutputPackagingElement.class);
     }
 
     @Override
@@ -234,5 +240,10 @@ public class JpsJavaModelSerializerExtension extends JpsModelSerializerExtension
       JpsModuleReference reference = JpsElementFactory.getInstance().createModuleReference(element.getAttributeValue("name"));
       return getService().createTestModuleOutput(reference);
     }
+
+    @Override
+    public void save(JpsTestModuleOutputPackagingElement element, Element tag) {
+      tag.setAttribute("name", element.getModuleReference().getModuleName());
+    }
   }
 }
diff --git a/jps/model-serialization/testData/sampleProject/.idea/artifacts/dir.xml b/jps/model-serialization/testData/sampleProject/.idea/artifacts/dir.xml
new file mode 100644 (file)
index 0000000..bbaca16
--- /dev/null
@@ -0,0 +1,17 @@
+<component name="ArtifactManager">
+  <artifact build-on-make="true" name="dir">
+    <output-path>$PROJECT_DIR$/out/artifacts/dir</output-path>
+    <root id="root">
+      <element id="archive" name="x.jar">
+        <element id="module-output" name="util" />
+      </element>
+      <element id="directory" name="lib">
+        <element id="library" level="module" name="log4j" module-name="util" />
+        <element id="library" level="project" name="junit" />
+        <element id="file-copy" path="$PROJECT_DIR$/main.iml" />
+        <element id="dir-copy" path="$PROJECT_DIR$/lib/junit-anno" />
+        <element id="extracted-dir" path="$PROJECT_DIR$/lib/junit.jar" path-in-jar="/junit/" />
+      </element>
+    </root>
+  </artifact>
+</component>
\ No newline at end of file
diff --git a/jps/model-serialization/testData/sampleProject/.idea/artifacts/jar.xml b/jps/model-serialization/testData/sampleProject/.idea/artifacts/jar.xml
new file mode 100644 (file)
index 0000000..7e19ac5
--- /dev/null
@@ -0,0 +1,10 @@
+<component name="ArtifactManager">
+  <artifact type="jar" name="jar">
+    <output-path>$PROJECT_DIR$/out/artifacts/jar</output-path>
+    <root id="archive" name="jar.jar">
+      <element id="module-output" name="main" />
+      <element id="module-output" name="util" />
+      <element id="artifact" artifact-name="dir" />
+    </root>
+  </artifact>
+</component>
\ No newline at end of file
diff --git a/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsArtifactSerializationTest.java b/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsArtifactSerializationTest.java
new file mode 100644 (file)
index 0000000..354c7db
--- /dev/null
@@ -0,0 +1,58 @@
+package org.jetbrains.jps.model.serialization;
+
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.testFramework.PlatformTestUtil;
+import org.jdom.Element;
+import org.jetbrains.jps.model.artifact.JpsArtifact;
+import org.jetbrains.jps.model.artifact.JpsArtifactService;
+import org.jetbrains.jps.model.serialization.artifact.JpsArtifactSerializer;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+import static org.jetbrains.jps.model.serialization.JpsProjectSerializationTest.SAMPLE_PROJECT_PATH;
+import static org.jetbrains.jps.model.serialization.JpsProjectSerializationTest.getFileInSampleProject;
+
+/**
+ * @author nik
+ */
+public class JpsArtifactSerializationTest extends JpsSerializationTestCase {
+  public void testLoadProject() {
+    loadProject(SAMPLE_PROJECT_PATH);
+    List<JpsArtifact> artifacts = getService().getArtifacts(myModel.getProject());
+    assertEquals(2, artifacts.size());
+    assertEquals("dir", artifacts.get(0).getName());
+    assertEquals("jar", artifacts.get(1).getName());
+  }
+
+  public void testSaveProject() {
+    loadProject(SAMPLE_PROJECT_PATH);
+    File[] artifactFiles = getFileInSampleProject(".idea/artifacts").listFiles();
+    assertNotNull(artifactFiles);
+    for (File file : artifactFiles) {
+      JpsArtifact artifact = getService().createReference(FileUtil.getNameWithoutExtension(file)).asExternal(myModel).resolve();
+      assertNotNull(artifact);
+      doTestSaveArtifact(artifact, file);
+    }
+  }
+
+  private static void doTestSaveArtifact(JpsArtifact artifact, File expectedFile) {
+    try {
+      Element actual = new Element("component").setAttribute("name", "ArtifactManager");
+      JpsArtifactSerializer.saveArtifact(artifact, actual);
+      JpsMacroExpander
+        expander = JpsProjectLoader.createProjectMacroExpander(Collections.<String, String>emptyMap(), getFileInSampleProject(""));
+      Element expected = JpsLoaderBase.loadRootElement(expectedFile, expander);
+      PlatformTestUtil.assertElementsEqual(expected, actual);
+    }
+    catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private static JpsArtifactService getService() {
+    return JpsArtifactService.getInstance();
+  }
+}
index 0465d1dedd2c36f5a27e3e71927588f78b9ca5bf..0a48048cbbd7edbcbf26afd45156f36a85ea4fdb 100644 (file)
@@ -18,7 +18,7 @@ import java.util.List;
  * @author nik
  */
 public class JpsProjectSerializationTest extends JpsSerializationTestCase {
-  private static final String SAMPLE_PROJECT_PATH = "/jps/model-serialization/testData/sampleProject";
+  public static final String SAMPLE_PROJECT_PATH = "/jps/model-serialization/testData/sampleProject";
 
   public void testLoadProject() {
     loadProject(SAMPLE_PROJECT_PATH);
@@ -89,8 +89,8 @@ public class JpsProjectSerializationTest extends JpsSerializationTestCase {
     }
   }
 
-  private static File getFileInSampleProject(String moduleFilePath) {
-    return new File(getTestDataFileAbsolutePath(SAMPLE_PROJECT_PATH + "/" + moduleFilePath));
+  public static File getFileInSampleProject(String relativePath) {
+    return new File(getTestDataFileAbsolutePath(SAMPLE_PROJECT_PATH + "/" + relativePath));
   }
 
   public void _testLoadIdeaProject() {