getElements();
+
+ @NotNull
+ E addChild(@NotNull JpsElementFactoryWithParameter factory, @NotNull P param);
+
+ @NotNull
+ E addChild(@NotNull JpsElementFactory factory);
+
+ E addChild(E element);
+
+ void removeChild(@NotNull E element);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsElementContainer.java b/jps/model-api/src/org/jetbrains/jps/model/JpsElementContainer.java
new file mode 100644
index 000000000000..969b3534fc53
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsElementContainer.java
@@ -0,0 +1,25 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public interface JpsElementContainer {
+
+ T getChild(@NotNull JpsElementKind kind);
+
+ @NotNull
+ &JpsElementFactory>
+ T setChild(@NotNull K kind);
+
+ @NotNull
+ &JpsElementFactoryWithParameter>
+ T setChild(@NotNull K kind, @NotNull P param);
+
+
+ T setChild(JpsElementKind kind, T child);
+
+
+ void removeChild(@NotNull JpsElementKind kind);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsElementFactory.java b/jps/model-api/src/org/jetbrains/jps/model/JpsElementFactory.java
new file mode 100644
index 000000000000..b06da51b9455
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsElementFactory.java
@@ -0,0 +1,12 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public interface JpsElementFactory {
+
+ @NotNull
+ E create(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsElementFactoryWithParameter.java b/jps/model-api/src/org/jetbrains/jps/model/JpsElementFactoryWithParameter.java
new file mode 100644
index 000000000000..13e9103789f6
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsElementFactoryWithParameter.java
@@ -0,0 +1,11 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public interface JpsElementFactoryWithParameter {
+ @NotNull
+ E create(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent, @NotNull P param);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsElementKind.java b/jps/model-api/src/org/jetbrains/jps/model/JpsElementKind.java
new file mode 100644
index 000000000000..4e47a07bfc5a
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsElementKind.java
@@ -0,0 +1,15 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public class JpsElementKind {
+
+ public void fireElementAdded(@NotNull JpsEventDispatcher dispatcher, @NotNull E element) {
+ }
+
+ public void fireElementRemoved(@NotNull JpsEventDispatcher dispatcher, @NotNull E element) {
+ }
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsElementProperties.java b/jps/model-api/src/org/jetbrains/jps/model/JpsElementProperties.java
new file mode 100644
index 000000000000..c238f1ce7459
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsElementProperties.java
@@ -0,0 +1,7 @@
+package org.jetbrains.jps.model;
+
+/**
+ * @author nik
+ */
+public abstract class JpsElementProperties {
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsElementReference.java b/jps/model-api/src/org/jetbrains/jps/model/JpsElementReference.java
new file mode 100644
index 000000000000..f09bbc71ace3
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsElementReference.java
@@ -0,0 +1,11 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author nik
+ */
+public interface JpsElementReference extends JpsElement {
+ @Nullable
+ T resolve();
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsElementType.java b/jps/model-api/src/org/jetbrains/jps/model/JpsElementType.java
new file mode 100644
index 000000000000..eb4f95707695
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsElementType.java
@@ -0,0 +1,10 @@
+package org.jetbrains.jps.model;
+
+/**
+ * @author nik
+ */
+public abstract class JpsElementType {
+ public abstract P createDefaultProperties();
+
+ public abstract P createCopy(P properties);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsEventDispatcher.java b/jps/model-api/src/org/jetbrains/jps/model/JpsEventDispatcher.java
new file mode 100644
index 000000000000..4c436ffce4c7
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsEventDispatcher.java
@@ -0,0 +1,23 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EventListener;
+
+/**
+ * @author nik
+ */
+public interface JpsEventDispatcher {
+ @NotNull
+ T getPublisher(Class listenerClass);
+
+ void fireElementRenamed(@NotNull JpsNamedElement element, @NotNull String oldName, @NotNull String newName);
+
+ void fireElementChanged(@NotNull JpsElement element);
+
+
+ void fireElementAdded(@NotNull T element, @NotNull JpsElementKind kind);
+
+
+ void fireElementRemoved(@NotNull T element, @NotNull JpsElementKind kind);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsGlobal.java b/jps/model-api/src/org/jetbrains/jps/model/JpsGlobal.java
new file mode 100644
index 000000000000..ea535b091670
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsGlobal.java
@@ -0,0 +1,15 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.library.JpsLibraryType;
+
+/**
+ * @author nik
+ */
+public interface JpsGlobal extends JpsCompositeElement, JpsReferenceableElement {
+ @NotNull
+ JpsLibrary addLibrary(@NotNull JpsLibraryType libraryType, final @NotNull String name);
+
+
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsModel.java b/jps/model-api/src/org/jetbrains/jps/model/JpsModel.java
new file mode 100644
index 000000000000..09780fa1861f
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsModel.java
@@ -0,0 +1,19 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public interface JpsModel {
+ @NotNull
+ JpsProject getProject();
+
+ @NotNull
+ JpsGlobal getGlobal();
+
+ @NotNull
+ JpsModel createModifiableModel(@NotNull JpsEventDispatcher eventDispatcher);
+
+ void commit();
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsNamedElement.java b/jps/model-api/src/org/jetbrains/jps/model/JpsNamedElement.java
new file mode 100644
index 000000000000..7c7bcc83afba
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsNamedElement.java
@@ -0,0 +1,13 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public interface JpsNamedElement extends JpsElement {
+ @NotNull
+ String getName();
+
+ void setName(@NotNull String name);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsParentElement.java b/jps/model-api/src/org/jetbrains/jps/model/JpsParentElement.java
new file mode 100644
index 000000000000..9a28f2bf39b1
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsParentElement.java
@@ -0,0 +1,7 @@
+package org.jetbrains.jps.model;
+
+/**
+ * @author nik
+ */
+public interface JpsParentElement extends JpsElement {
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsProject.java b/jps/model-api/src/org/jetbrains/jps/model/JpsProject.java
new file mode 100644
index 000000000000..0beb26b8a514
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsProject.java
@@ -0,0 +1,27 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.library.JpsLibraryType;
+import org.jetbrains.jps.model.module.JpsModule;
+import org.jetbrains.jps.model.module.JpsModuleType;
+
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public interface JpsProject extends JpsCompositeElement, JpsReferenceableElement {
+
+ @NotNull
+ JpsModule addModule(@NotNull JpsModuleType> moduleType, @NotNull String name);
+
+ @NotNull
+ JpsLibrary addLibrary(@NotNull JpsLibraryType> libraryType, @NotNull String name);
+
+ @NotNull
+ List extends JpsLibrary> getLibraries();
+
+ @NotNull
+ List extends JpsModule> getModules();
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsReferenceableElement.java b/jps/model-api/src/org/jetbrains/jps/model/JpsReferenceableElement.java
new file mode 100644
index 000000000000..4df008cce68c
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsReferenceableElement.java
@@ -0,0 +1,11 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public interface JpsReferenceableElement {
+ @NotNull
+ JpsElementReference createReference(JpsParentElement parent);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsTypedData.java b/jps/model-api/src/org/jetbrains/jps/model/JpsTypedData.java
new file mode 100644
index 000000000000..fee5e2e12a66
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsTypedData.java
@@ -0,0 +1,16 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public interface JpsTypedData extends JpsElement {
+ @NotNull
+ JpsElementType
getType();
+
+ @NotNull
+ P getProperties();
+
+ void setProperties(@NotNull P properties);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsUrlList.java b/jps/model-api/src/org/jetbrains/jps/model/JpsUrlList.java
new file mode 100644
index 000000000000..d8040d206771
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsUrlList.java
@@ -0,0 +1,17 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public interface JpsUrlList extends JpsElement {
+ @NotNull
+ List getUrls();
+
+ void addUrl(@NotNull String url);
+
+ void removeUrl(@NotNull String url);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/JpsUrlListChangeListener.java b/jps/model-api/src/org/jetbrains/jps/model/JpsUrlListChangeListener.java
new file mode 100644
index 000000000000..0d1450deaaae
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/JpsUrlListChangeListener.java
@@ -0,0 +1,12 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public interface JpsUrlListChangeListener {
+ void urlAdded(@NotNull T element, @NotNull String url);
+
+ void urlRemoved(@NotNull T element, @NotNull String url);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/SimpleJpsElement.java b/jps/model-api/src/org/jetbrains/jps/model/SimpleJpsElement.java
new file mode 100644
index 000000000000..09a565fda058
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/SimpleJpsElement.java
@@ -0,0 +1,13 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public interface SimpleJpsElement extends JpsElement {
+ @NotNull
+ P getProperties();
+
+ void setProperties(@NotNull P properties);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleExtension.java b/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleExtension.java
new file mode 100644
index 000000000000..1ac6c18b42a4
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleExtension.java
@@ -0,0 +1,21 @@
+package org.jetbrains.jps.model.java;
+
+import org.jetbrains.jps.model.JpsElement;
+
+/**
+ * @author nik
+ */
+public interface JavaModuleExtension extends JpsElement {
+
+ String getOutputUrl();
+
+ void setOutputUrl(String outputUrl);
+
+ String getTestOutputUrl();
+
+ void setTestOutputUrl(String testOutputUrl);
+
+ LanguageLevel getLanguageLevel();
+
+ void setLanguageLevel(LanguageLevel languageLevel);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/JavaSourceRootProperties.java b/jps/model-api/src/org/jetbrains/jps/model/java/JavaSourceRootProperties.java
new file mode 100644
index 000000000000..716fc48a91e0
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/java/JavaSourceRootProperties.java
@@ -0,0 +1,22 @@
+package org.jetbrains.jps.model.java;
+
+import org.jetbrains.jps.model.JpsElementProperties;
+
+/**
+ * @author nik
+ */
+public class JavaSourceRootProperties extends JpsElementProperties {
+ private final String myPackagePrefix;
+
+ public JavaSourceRootProperties() {
+ myPackagePrefix = "";
+ }
+
+ public JavaSourceRootProperties(String packagePrefix) {
+ myPackagePrefix = packagePrefix;
+ }
+
+ public String getPackagePrefix() {
+ return myPackagePrefix;
+ }
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/JavaSourceRootType.java b/jps/model-api/src/org/jetbrains/jps/model/java/JavaSourceRootType.java
new file mode 100644
index 000000000000..0428014e8c2b
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/java/JavaSourceRootType.java
@@ -0,0 +1,21 @@
+package org.jetbrains.jps.model.java;
+
+import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
+
+/**
+ * @author nik
+ */
+public class JavaSourceRootType extends JpsModuleSourceRootType {
+ public static final JavaSourceRootType SOURCE = new JavaSourceRootType();
+ public static final JavaSourceRootType TEST_SOURCE = new JavaSourceRootType();
+
+ @Override
+ public JavaSourceRootProperties createDefaultProperties() {
+ return new JavaSourceRootProperties();
+ }
+
+ @Override
+ public JavaSourceRootProperties createCopy(JavaSourceRootProperties properties) {
+ return new JavaSourceRootProperties(properties.getPackagePrefix());
+ }
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/JpsJavaLibraryType.java b/jps/model-api/src/org/jetbrains/jps/model/java/JpsJavaLibraryType.java
new file mode 100644
index 000000000000..d28bb62867fb
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/java/JpsJavaLibraryType.java
@@ -0,0 +1,21 @@
+package org.jetbrains.jps.model.java;
+
+import org.jetbrains.jps.model.DummyJpsElementProperties;
+import org.jetbrains.jps.model.library.JpsLibraryType;
+
+/**
+ * @author nik
+ */
+public class JpsJavaLibraryType extends JpsLibraryType {
+ public static final JpsJavaLibraryType INSTANCE = new JpsJavaLibraryType();
+
+ @Override
+ public DummyJpsElementProperties createDefaultProperties() {
+ return DummyJpsElementProperties.INSTANCE;
+ }
+
+ @Override
+ public DummyJpsElementProperties createCopy(DummyJpsElementProperties properties) {
+ return DummyJpsElementProperties.INSTANCE;
+ }
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/JpsJavaModuleType.java b/jps/model-api/src/org/jetbrains/jps/model/java/JpsJavaModuleType.java
new file mode 100644
index 000000000000..7a9c2b643606
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/java/JpsJavaModuleType.java
@@ -0,0 +1,21 @@
+package org.jetbrains.jps.model.java;
+
+import org.jetbrains.jps.model.DummyJpsElementProperties;
+import org.jetbrains.jps.model.module.JpsModuleType;
+
+/**
+ * @author nik
+ */
+public class JpsJavaModuleType extends JpsModuleType {
+ public static final JpsJavaModuleType INSTANCE = new JpsJavaModuleType();
+
+ @Override
+ public DummyJpsElementProperties createDefaultProperties() {
+ return DummyJpsElementProperties.INSTANCE;
+ }
+
+ @Override
+ public DummyJpsElementProperties createCopy(DummyJpsElementProperties properties) {
+ return DummyJpsElementProperties.INSTANCE;
+ }
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/LanguageLevel.java b/jps/model-api/src/org/jetbrains/jps/model/java/LanguageLevel.java
new file mode 100644
index 000000000000..5cf1c66de6af
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/java/LanguageLevel.java
@@ -0,0 +1,7 @@
+package org.jetbrains.jps.model.java;
+
+/**
+ * @author nik
+ */
+public enum LanguageLevel {
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibrary.java b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibrary.java
new file mode 100644
index 000000000000..45293113ecfe
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibrary.java
@@ -0,0 +1,26 @@
+package org.jetbrains.jps.model.library;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsNamedElement;
+import org.jetbrains.jps.model.JpsParentElement;
+import org.jetbrains.jps.model.JpsReferenceableElement;
+
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public interface JpsLibrary extends JpsNamedElement, JpsReferenceableElement {
+
+ @NotNull
+ List getUrls(@NotNull JpsLibraryRootType rootType);
+
+ void addUrl(@NotNull String url, @NotNull JpsLibraryRootType rootType);
+
+ void removeUrl(@NotNull String url, @NotNull JpsLibraryRootType rootType);
+
+ void delete();
+
+ @NotNull
+ JpsLibraryReference createReference(JpsParentElement parent);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryListener.java b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryListener.java
new file mode 100644
index 000000000000..050544c1d010
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryListener.java
@@ -0,0 +1,13 @@
+package org.jetbrains.jps.model.library;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EventListener;
+
+/**
+ * @author nik
+ */
+public interface JpsLibraryListener extends EventListener {
+ void libraryAdded(@NotNull JpsLibrary library);
+ void libraryRemoved(@NotNull JpsLibrary library);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryReference.java b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryReference.java
new file mode 100644
index 000000000000..c752520a13fd
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryReference.java
@@ -0,0 +1,12 @@
+package org.jetbrains.jps.model.library;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElementReference;
+
+/**
+ * @author nik
+ */
+public interface JpsLibraryReference extends JpsElementReference {
+ @NotNull
+ String getLibraryName();
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryRoot.java b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryRoot.java
new file mode 100644
index 000000000000..49254236d441
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryRoot.java
@@ -0,0 +1,18 @@
+package org.jetbrains.jps.model.library;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElement;
+
+/**
+ * @author nik
+ */
+public interface JpsLibraryRoot extends JpsElement {
+ @NotNull
+ JpsLibraryRootType getRootType();
+
+ @NotNull
+ String getUrl();
+
+ @NotNull
+ JpsLibrary getLibrary();
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryRootListener.java b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryRootListener.java
new file mode 100644
index 000000000000..1ef06776865e
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryRootListener.java
@@ -0,0 +1,13 @@
+package org.jetbrains.jps.model.library;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EventListener;
+
+/**
+ * @author nik
+ */
+public interface JpsLibraryRootListener extends EventListener {
+ void rootAdded(@NotNull JpsLibraryRoot root);
+ void rootRemoved(@NotNull JpsLibraryRoot root);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryRootType.java b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryRootType.java
new file mode 100644
index 000000000000..70afc3f5e8ee
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryRootType.java
@@ -0,0 +1,24 @@
+package org.jetbrains.jps.model.library;
+
+/**
+ * @author nik
+ */
+public class JpsLibraryRootType {
+ public static final JpsLibraryRootType COMPILED = new JpsLibraryRootType(JpsOrderRootType.COMPILED, false);
+ public static final JpsLibraryRootType SOURCES = new JpsLibraryRootType(JpsOrderRootType.SOURCES, false);
+ private final boolean myJarDirectory;
+ private final JpsOrderRootType myType;
+
+ public JpsLibraryRootType(JpsOrderRootType type, boolean jarDirectory) {
+ myType = type;
+ myJarDirectory = jarDirectory;
+ }
+
+ public boolean isJarDirectory() {
+ return myJarDirectory;
+ }
+
+ public JpsOrderRootType getType() {
+ return myType;
+ }
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryType.java b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryType.java
new file mode 100644
index 000000000000..e569468d37c1
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibraryType.java
@@ -0,0 +1,10 @@
+package org.jetbrains.jps.model.library;
+
+import org.jetbrains.jps.model.JpsElementProperties;
+import org.jetbrains.jps.model.JpsElementType;
+
+/**
+ * @author nik
+ */
+public abstract class JpsLibraryType extends JpsElementType
{
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/library/JpsOrderRootType.java b/jps/model-api/src/org/jetbrains/jps/model/library/JpsOrderRootType.java
new file mode 100644
index 000000000000..78f3ff44f0d0
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/library/JpsOrderRootType.java
@@ -0,0 +1,13 @@
+package org.jetbrains.jps.model.library;
+
+/**
+ * @author nik
+ */
+public abstract class JpsOrderRootType {
+ public static final JpsOrderRootType COMPILED = new JpsOrderRootType() {
+ };
+ public static final JpsOrderRootType SOURCES = new JpsOrderRootType() {
+ };
+ public static final JpsOrderRootType DOCUMENTATION = new JpsOrderRootType() {
+ };
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/DependenciesList.java b/jps/model-api/src/org/jetbrains/jps/model/module/DependenciesList.java
new file mode 100644
index 000000000000..43cfa47485ce
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/DependenciesList.java
@@ -0,0 +1,21 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElement;
+import org.jetbrains.jps.model.library.JpsLibrary;
+
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public interface DependenciesList extends JpsElement {
+ @NotNull
+ JpsModuleDependency addModuleDependency(@NotNull JpsModule module);
+
+ @NotNull
+ JpsLibraryDependency addLibraryDependency(@NotNull JpsLibrary libraryElement);
+
+ @NotNull
+ List extends JpsDependencyElement> getDependencies();
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsDependencyElement.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsDependencyElement.java
new file mode 100644
index 000000000000..45655c8ba102
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsDependencyElement.java
@@ -0,0 +1,9 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.jps.model.JpsElement;
+
+/**
+ * @author nik
+ */
+public interface JpsDependencyElement extends JpsElement {
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsLibraryDependency.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsLibraryDependency.java
new file mode 100644
index 000000000000..d6b9c9773c4f
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsLibraryDependency.java
@@ -0,0 +1,12 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.library.JpsLibraryReference;
+
+/**
+ * @author nik
+ */
+public interface JpsLibraryDependency extends JpsDependencyElement {
+ @NotNull
+ JpsLibraryReference getLibraryReference();
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModule.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModule.java
new file mode 100644
index 000000000000..a1ac2b047a88
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModule.java
@@ -0,0 +1,41 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public interface JpsModule extends JpsNamedElement, JpsReferenceableElement {
+ @NotNull
+ JpsUrlList getContentRootsList();
+
+ @NotNull
+ JpsUrlList getExcludeRootsList();
+
+
+ @NotNull
+ List extends JpsModuleSourceRoot> getSourceRoots();
+
+ @NotNull
+
+ JpsModuleSourceRoot addSourceRoot(@NotNull JpsModuleSourceRootType
rootType, @NotNull String url);
+
+ @NotNull
+
+ JpsModuleSourceRoot addSourceRoot(@NotNull JpsModuleSourceRootType
rootType, @NotNull String url, @NotNull P properties);
+
+ void removeSourceRoot(@NotNull JpsModuleSourceRootType rootType, @NotNull String url);
+
+ DependenciesList getDependenciesList();
+
+ @NotNull
+ JpsElementContainer getContainer();
+
+ @NotNull
+ JpsModuleReference createReference(JpsParentElement parent);
+
+ void delete();
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleContentRootsListener.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleContentRootsListener.java
new file mode 100644
index 000000000000..28320c8fe5ef
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleContentRootsListener.java
@@ -0,0 +1,9 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.jps.model.JpsUrlListChangeListener;
+
+/**
+ * @author nik
+ */
+public interface JpsModuleContentRootsListener extends JpsUrlListChangeListener {
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleDependency.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleDependency.java
new file mode 100644
index 000000000000..88d707794ec4
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleDependency.java
@@ -0,0 +1,11 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public interface JpsModuleDependency extends JpsDependencyElement {
+ @NotNull
+ JpsModuleReference getModuleReference();
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleExcludeRootsListener.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleExcludeRootsListener.java
new file mode 100644
index 000000000000..50b70a795913
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleExcludeRootsListener.java
@@ -0,0 +1,9 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.jps.model.JpsUrlListChangeListener;
+
+/**
+ * @author nik
+ */
+public interface JpsModuleExcludeRootsListener extends JpsUrlListChangeListener {
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleListener.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleListener.java
new file mode 100644
index 000000000000..73d20ad51fdd
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleListener.java
@@ -0,0 +1,14 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.module.JpsModule;
+
+import java.util.EventListener;
+
+/**
+ * @author nik
+ */
+public interface JpsModuleListener extends EventListener {
+ void moduleAdded(@NotNull JpsModule module);
+ void moduleRemoved(@NotNull JpsModule module);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleReference.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleReference.java
new file mode 100644
index 000000000000..90a35bf07ec3
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleReference.java
@@ -0,0 +1,12 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElementReference;
+
+/**
+ * @author nik
+ */
+public interface JpsModuleReference extends JpsElementReference {
+ @NotNull
+ String getModuleName();
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleSourceRoot.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleSourceRoot.java
new file mode 100644
index 000000000000..36eb82c2c607
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleSourceRoot.java
@@ -0,0 +1,23 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jps.model.JpsElement;
+import org.jetbrains.jps.model.JpsElementProperties;
+
+/**
+ * @author nik
+ */
+public interface JpsModuleSourceRoot extends JpsElement {
+ @NotNull
+ JpsModuleSourceRootType> getRootType();
+
+ @Nullable
+ P getProperties(@NotNull JpsModuleSourceRootType
type);
+
+
+ void setProperties(JpsModuleSourceRootType
type, P properties);
+
+ @NotNull
+ String getUrl();
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleSourceRootListener.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleSourceRootListener.java
new file mode 100644
index 000000000000..9b1ef089315a
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleSourceRootListener.java
@@ -0,0 +1,14 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EventListener;
+
+/**
+ * @author nik
+ */
+public interface JpsModuleSourceRootListener extends EventListener {
+ void sourceRootAdded(@NotNull JpsModuleSourceRoot root);
+ void sourceRootRemoved(@NotNull JpsModuleSourceRoot root);
+ void sourceRootChanged(@NotNull JpsModuleSourceRoot root);
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleSourceRootType.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleSourceRootType.java
new file mode 100644
index 000000000000..2d5a01706f83
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleSourceRootType.java
@@ -0,0 +1,10 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.jps.model.JpsElementProperties;
+import org.jetbrains.jps.model.JpsElementType;
+
+/**
+ * @author nik
+ */
+public abstract class JpsModuleSourceRootType
extends JpsElementType
{
+}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleType.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleType.java
new file mode 100644
index 000000000000..a5e720b73b0a
--- /dev/null
+++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModuleType.java
@@ -0,0 +1,11 @@
+package org.jetbrains.jps.model.module;
+
+import org.jetbrains.jps.model.JpsElementProperties;
+import org.jetbrains.jps.model.JpsElementType;
+
+/**
+ * @author nik
+ */
+public abstract class JpsModuleType
extends JpsElementType
{
+
+}
diff --git a/jps/model-impl/jps-model-impl.iml b/jps/model-impl/jps-model-impl.iml
new file mode 100644
index 000000000000..4a17b3a41db1
--- /dev/null
+++ b/jps/model-impl/jps-model-impl.iml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsCompositeElementBase.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsCompositeElementBase.java
new file mode 100644
index 000000000000..c1b38364d791
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsCompositeElementBase.java
@@ -0,0 +1,35 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+/**
+ * @author nik
+ */
+public abstract class JpsCompositeElementBase> extends JpsElementBase implements JpsCompositeElement {
+ protected final JpsElementContainerImpl myContainer;
+ protected final JpsModel myModel;
+
+ protected JpsCompositeElementBase(JpsModel model, JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(eventDispatcher, parent);
+ myModel = model;
+ myContainer = new JpsElementContainerImpl(model, eventDispatcher, this);
+ }
+
+ protected JpsCompositeElementBase(JpsCompositeElementBase original, JpsModel model, JpsEventDispatcher dispatcher,
+ JpsParentElement parent) {
+ super(original, dispatcher, parent);
+ myModel = model;
+ myContainer = new JpsElementContainerImpl(original.myContainer, model, dispatcher, this);
+ }
+
+ public void applyChanges(@NotNull Self element) {
+ myContainer.applyChanges(element.myContainer);
+ }
+
+ @Override
+ @NotNull
+ public JpsElementContainerImpl getContainer() {
+ return myContainer;
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementBase.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementBase.java
new file mode 100644
index 000000000000..12c982d8f708
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementBase.java
@@ -0,0 +1,41 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+/**
+ * @author nik
+ */
+public abstract class JpsElementBase> implements JpsElement, JpsElement.BulkModificationSupport {
+ private JpsEventDispatcher myEventDispatcher;
+ protected JpsParentElement myParent;
+
+ protected JpsElementBase(JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ myEventDispatcher = eventDispatcher;
+ myParent = parent;
+ }
+
+ public JpsElementBase(JpsElementBase original, JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ myEventDispatcher = eventDispatcher;
+ myParent = parent;
+ }
+
+ protected JpsEventDispatcher getEventDispatcher() {
+ return myEventDispatcher;
+ }
+
+ @NotNull
+ @Override
+ public BulkModificationSupport> getBulkModificationSupport() {
+ return this;
+ }
+
+ @NotNull
+ public abstract Self createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent);
+
+ public abstract void applyChanges(@NotNull Self modified);
+
+ public JpsParentElement getParent() {
+ return myParent;
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementCollectionImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementCollectionImpl.java
new file mode 100644
index 000000000000..3afa780758c9
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementCollectionImpl.java
@@ -0,0 +1,107 @@
+package org.jetbrains.jps.model.impl;
+
+import com.intellij.util.SmartList;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+import java.util.*;
+
+/**
+ * @author nik
+ */
+public class JpsElementCollectionImpl extends JpsElementBase> implements JpsElementCollection {
+ private final List myElements;
+ private final JpsModel myModel;
+ private final Map myCopyToOriginal;
+ private final JpsElementKind myKind;
+
+ public JpsElementCollectionImpl(JpsElementKind kind, JpsModel model, JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(eventDispatcher, parent);
+ myKind = kind;
+ myModel = model;
+ myElements = new SmartList();
+ myCopyToOriginal = null;
+ }
+
+ public JpsElementCollectionImpl(JpsElementCollectionImpl original,
+ JpsModel model,
+ JpsEventDispatcher eventDispatcher,
+ JpsParentElement parent) {
+ super(original, eventDispatcher, parent);
+ myKind = original.myKind;
+ myModel = model;
+ myElements = new SmartList();
+ myCopyToOriginal = new HashMap();
+ for (E e : original.myElements) {
+ //noinspection unchecked
+ final E copy = (E)e.getBulkModificationSupport().createCopy(model, eventDispatcher, parent);
+ myElements.add(copy);
+ myCopyToOriginal.put(copy, e);
+ }
+ }
+
+ @Override
+ public List getElements() {
+ return myElements;
+ }
+
+ @NotNull
+ @Override
+ public E addChild(@NotNull JpsElementFactoryWithParameter factory, @NotNull P param) {
+ return addChild(factory.create(myModel, getEventDispatcher(), myParent, param));
+ }
+
+ @NotNull
+ @Override
+ public E addChild(@NotNull JpsElementFactory factory) {
+ return addChild(factory.create(myModel, getEventDispatcher(), myParent));
+ }
+
+ @Override
+ public E addChild(E element) {
+ myElements.add(element);
+ getEventDispatcher().fireElementAdded(element, myKind);
+ return element;
+ }
+
+ @Override
+ public void removeChild(@NotNull E element) {
+ final boolean removed = myElements.remove(element);
+ if (removed) {
+ getEventDispatcher().fireElementRemoved(element, myKind);
+ }
+ }
+
+ @NotNull
+ @Override
+ public JpsElementCollectionImpl createCopy(@NotNull JpsModel model,
+ @NotNull JpsEventDispatcher eventDispatcher,
+ JpsParentElement parent) {
+ return new JpsElementCollectionImpl(this, model, eventDispatcher, parent);
+ }
+
+ public void applyChanges(@NotNull JpsElementCollectionImpl modified) {
+ Set toRemove = new LinkedHashSet(myElements);
+ List toAdd = new ArrayList();
+ final Map copyToOriginal = modified.myCopyToOriginal;
+ for (E element : modified.myElements) {
+ final E original = copyToOriginal != null ? copyToOriginal.get(element) : null;
+ if (original != null) {
+ //noinspection unchecked
+ ((BulkModificationSupport)original.getBulkModificationSupport()).applyChanges(element);
+ toRemove.remove(original);
+ }
+ else {
+ //noinspection unchecked
+ final E copy = (E)element.getBulkModificationSupport().createCopy(myModel, getEventDispatcher(), myParent);
+ toAdd.add(copy);
+ }
+ }
+ for (E e : toRemove) {
+ removeChild(e);
+ }
+ for (E e : toAdd) {
+ addChild(e);
+ }
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementCollectionKind.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementCollectionKind.java
new file mode 100644
index 000000000000..d5eb0b048b1d
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementCollectionKind.java
@@ -0,0 +1,24 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+/**
+ * @author nik
+ */
+public class JpsElementCollectionKind> extends JpsElementKind>
+ implements JpsElementFactory> {
+ private final JpsElementKind myElementKind;
+
+ public JpsElementCollectionKind(JpsElementKind elementKind) {
+ myElementKind = elementKind;
+ }
+
+ @NotNull
+ @Override
+ public JpsElementCollectionImpl create(@NotNull JpsModel model,
+ @NotNull JpsEventDispatcher eventDispatcher,
+ JpsParentElement parent) {
+ return new JpsElementCollectionImpl(myElementKind, model, eventDispatcher, parent);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementContainerImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementContainerImpl.java
new file mode 100644
index 000000000000..a231add0dd96
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsElementContainerImpl.java
@@ -0,0 +1,98 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author nik
+ */
+public class JpsElementContainerImpl implements JpsElementContainer {
+ private final Map, JpsElement> myElements = new HashMap, JpsElement>();
+ private final @NotNull JpsModel myModel;
+ private final @NotNull JpsEventDispatcher myEventDispatcher;
+ private final @NotNull JpsParentElement myParent;
+
+ public JpsElementContainerImpl(@NotNull JpsModel model,
+ @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ myModel = model;
+ myEventDispatcher = eventDispatcher;
+ myParent = parent;
+ }
+
+ public JpsElementContainerImpl(@NotNull JpsElementContainerImpl original, @NotNull JpsModel model,
+ @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ myModel = model;
+ myEventDispatcher = eventDispatcher;
+ myParent = parent;
+ for (Map.Entry, JpsElement> entry : original.myElements.entrySet()) {
+ final JpsElementKind kind = entry.getKey();
+ myElements.put(kind, entry.getValue().getBulkModificationSupport().createCopy(myModel, myEventDispatcher, myParent));
+ }
+ }
+
+ @Override
+ public T getChild(@NotNull JpsElementKind kind) {
+ //noinspection unchecked
+ return (T)myElements.get(kind);
+ }
+
+ @NotNull
+ @Override
+ public & JpsElementFactoryWithParameter> T setChild(@NotNull K kind,
+ @NotNull P param) {
+ final T child = kind.create(myModel, myEventDispatcher, myParent, param);
+ return setChild(kind, child);
+ }
+
+ @NotNull
+ @Override
+ public & JpsElementFactory> T setChild(@NotNull K kind) {
+ final T child = kind.create(myModel, myEventDispatcher, myParent);
+ return setChild(kind, child);
+ }
+
+ @Override
+ public T setChild(JpsElementKind kind, T child) {
+ myElements.put(kind, child);
+ myEventDispatcher.fireElementAdded(child, kind);
+ return child;
+ }
+
+ @Override
+ public void removeChild(@NotNull JpsElementKind kind) {
+ //noinspection unchecked
+ final T removed = (T)myElements.remove(kind);
+ myEventDispatcher.fireElementRemoved(removed, kind);
+ }
+
+ public void applyChanges(@NotNull JpsElementContainerImpl modified) {
+ for (JpsElementKind> kind : myElements.keySet()) {
+ applyChanges(kind, modified);
+ }
+ for (JpsElementKind> kind : modified.myElements.keySet()) {
+ if (!myElements.containsKey(kind)) {
+ applyChanges(kind, modified);
+ }
+ }
+ }
+
+ private void applyChanges(JpsElementKind kind, JpsElementContainerImpl modified) {
+ final T child = getChild(kind);
+ final T modifiedChild = modified.getChild(kind);
+ if (child != null && modifiedChild != null) {
+ final JpsElement.BulkModificationSupport modificationSupport = child.getBulkModificationSupport();
+ //noinspection unchecked
+ modificationSupport.applyChanges(modifiedChild);
+ }
+ else if (modifiedChild == null) {
+ removeChild(kind);
+ }
+ else {
+ //noinspection unchecked
+ setChild(kind, (T)modifiedChild.getBulkModificationSupport().createCopy(myModel, myEventDispatcher, myParent));
+ }
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsEventDispatcherBase.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsEventDispatcherBase.java
new file mode 100644
index 000000000000..07691513f775
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsEventDispatcherBase.java
@@ -0,0 +1,40 @@
+package org.jetbrains.jps.model.impl;
+
+import com.intellij.util.EventDispatcher;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElement;
+import org.jetbrains.jps.model.JpsElementKind;
+import org.jetbrains.jps.model.JpsEventDispatcher;
+
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author nik
+ */
+public abstract class JpsEventDispatcherBase implements JpsEventDispatcher {
+ private Map, EventDispatcher>> myDispatchers = new HashMap, EventDispatcher>>();
+
+ @NotNull
+ @Override
+ public T getPublisher(Class listenerClass) {
+ EventDispatcher> dispatcher = myDispatchers.get(listenerClass);
+ if (dispatcher == null) {
+ dispatcher = EventDispatcher.create(listenerClass);
+ myDispatchers.put(listenerClass, dispatcher);
+ }
+ //noinspection unchecked
+ return (T)dispatcher.getMulticaster();
+ }
+
+ @Override
+ public void fireElementAdded(@NotNull T element, @NotNull JpsElementKind kind) {
+ kind.fireElementAdded(this, element);
+ }
+
+ @Override
+ public void fireElementRemoved(@NotNull T element, @NotNull JpsElementKind kind) {
+ kind.fireElementRemoved(this, element);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsGlobalElementReference.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsGlobalElementReference.java
new file mode 100644
index 000000000000..4e245d5dcf98
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsGlobalElementReference.java
@@ -0,0 +1,33 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+/**
+ * @author nik
+ */
+public class JpsGlobalElementReference extends JpsElementBase implements JpsElementReference {
+ private final JpsModel myModel;
+
+ public JpsGlobalElementReference(JpsModel model, JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(eventDispatcher, parent);
+ myModel = model;
+ }
+
+ @Override
+ public JpsGlobal resolve() {
+ return myModel.getGlobal();
+ }
+
+ @NotNull
+ @Override
+ public JpsGlobalElementReference createCopy(@NotNull JpsModel model,
+ @NotNull JpsEventDispatcher eventDispatcher,
+ JpsParentElement parent) {
+ return new JpsGlobalElementReference(model, eventDispatcher, parent);
+ }
+
+ @Override
+ public void applyChanges(@NotNull JpsGlobalElementReference modified) {
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsGlobalImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsGlobalImpl.java
new file mode 100644
index 000000000000..b6cbe9e08d04
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsGlobalImpl.java
@@ -0,0 +1,41 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.library.JpsLibraryType;
+import org.jetbrains.jps.model.library.impl.JpsLibraryImpl;
+import org.jetbrains.jps.model.library.impl.JpsLibraryKind;
+
+/**
+ * @author nik
+ */
+public class JpsGlobalImpl extends JpsCompositeElementBase implements JpsGlobal {
+ public JpsGlobalImpl(JpsModel model, JpsEventDispatcher eventDispatcher) {
+ super(model, eventDispatcher, null);
+ myContainer.setChild(JpsLibraryKind.LIBRARIES_COLLECTION_KIND);
+ }
+
+ public JpsGlobalImpl(JpsGlobalImpl original, JpsModel model, JpsEventDispatcher eventDispatcher) {
+ super(original, model, eventDispatcher, null);
+ }
+
+ @NotNull
+ @Override
+ public JpsGlobalImpl createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new JpsGlobalImpl(this, model, eventDispatcher);
+ }
+
+ @NotNull
+ @Override
+ public JpsLibrary addLibrary(@NotNull JpsLibraryType libraryType, @NotNull final String name) {
+ final JpsElementCollectionImpl collection = myContainer.getChild(JpsLibraryKind.LIBRARIES_COLLECTION_KIND);
+ return collection.addChild(new JpsLibraryImpl(name, libraryType, myModel, getEventDispatcher(), collection));
+ }
+
+ @NotNull
+ @Override
+ public JpsElementReference createReference(JpsParentElement parent) {
+ return new JpsGlobalElementReference(myModel, getEventDispatcher(), parent);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsModelImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsModelImpl.java
new file mode 100644
index 000000000000..ae6b7f4d1f8c
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsModelImpl.java
@@ -0,0 +1,51 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsEventDispatcher;
+import org.jetbrains.jps.model.JpsModel;
+
+/**
+ * @author nik
+ */
+public class JpsModelImpl implements JpsModel {
+ private JpsProjectImpl myProject;
+ private JpsGlobalImpl myGlobal;
+ private JpsModelImpl myOriginalModel;
+
+ public JpsModelImpl(JpsEventDispatcher eventDispatcher) {
+ myProject = new JpsProjectImpl(this, eventDispatcher);
+ myGlobal = new JpsGlobalImpl(this, eventDispatcher);
+ }
+
+ private JpsModelImpl(JpsModelImpl original, JpsEventDispatcher eventDispatcher) {
+ myOriginalModel = original;
+ myProject = new JpsProjectImpl(original.myProject, this, eventDispatcher);
+ myGlobal = new JpsGlobalImpl(original.myGlobal, this, eventDispatcher);
+ }
+
+ @NotNull
+ public JpsProjectImpl getProject() {
+ return myProject;
+ }
+
+ @NotNull
+ public JpsGlobalImpl getGlobal() {
+ return myGlobal;
+ }
+
+ @NotNull
+ @Override
+ public JpsModel createModifiableModel(@NotNull JpsEventDispatcher eventDispatcher) {
+ return new JpsModelImpl(this, eventDispatcher);
+ }
+
+ @Override
+ public void commit() {
+ myOriginalModel.applyChanges(this);
+ }
+
+ private void applyChanges(@NotNull JpsModelImpl modifiedCopy) {
+ myProject.applyChanges(modifiedCopy.myProject);
+ myGlobal.applyChanges(modifiedCopy.myGlobal);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsNamedCompositeElementBase.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsNamedCompositeElementBase.java
new file mode 100644
index 000000000000..8c488b35d6e4
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsNamedCompositeElementBase.java
@@ -0,0 +1,47 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+/**
+ * @author nik
+ */
+public abstract class JpsNamedCompositeElementBase, Parent extends JpsCompositeElementBase> extends
+ JpsCompositeElementBase
+ implements JpsNamedElement {
+ private String myName;
+
+ protected JpsNamedCompositeElementBase(JpsModel model,
+ JpsEventDispatcher eventDispatcher,
+ @NotNull String name, JpsParentElement parent) {
+ super(model, eventDispatcher, parent);
+ myName = name;
+ }
+
+ protected JpsNamedCompositeElementBase(JpsNamedCompositeElementBase original,
+ JpsModel model,
+ JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(original, model, eventDispatcher, parent);
+ myName = original.myName;
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return myName;
+ }
+
+ public void applyChanges(@NotNull Self modified) {
+ super.applyChanges(modified);
+ setName(modified.myName);
+ }
+
+ @Override
+ public void setName(@NotNull String name) {
+ if (!myName.equals(name)) {
+ String oldName = myName;
+ myName = name;
+ getEventDispatcher().fireElementRenamed(this, oldName, name);
+ }
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsNamedElementReferenceBase.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsNamedElementReferenceBase.java
new file mode 100644
index 000000000000..9e083cf5a66b
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsNamedElementReferenceBase.java
@@ -0,0 +1,45 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public abstract class JpsNamedElementReferenceBase> extends JpsCompositeElementBase implements JpsElementReference {
+ private static final JpsElementKind> PARENT_REFERENCE_KIND = new JpsElementKind>();
+ private final JpsElementCollectionKind extends T> myCollectionKind;
+ protected final String myElementName;
+
+ protected JpsNamedElementReferenceBase(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, @NotNull JpsElementCollectionKind extends T> kind, @NotNull String elementName,
+ @NotNull JpsElementReference extends JpsCompositeElement> parentReference, JpsParentElement parent) {
+ super(model, eventDispatcher, parent);
+ myCollectionKind = kind;
+ myElementName = elementName;
+ myContainer.setChild(PARENT_REFERENCE_KIND, parentReference);
+ }
+
+ protected JpsNamedElementReferenceBase(JpsNamedElementReferenceBase original,
+ JpsModel model, JpsEventDispatcher eventDispatcher,
+ JpsParentElement parent) {
+ super(original, model, eventDispatcher, parent);
+ myCollectionKind = original.myCollectionKind;
+ myElementName = original.myElementName;
+ }
+
+ @Override
+ public T resolve() {
+ final JpsCompositeElement parent = myContainer.getChild(PARENT_REFERENCE_KIND).resolve();
+ if (parent == null) return null;
+
+ final List extends T> elements = parent.getContainer().getChild(myCollectionKind).getElements();
+ for (T element : elements) {
+ if (element.getName().equals(myElementName)) {
+ return element;
+ }
+ }
+ return null;
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsProjectElementReference.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsProjectElementReference.java
new file mode 100644
index 000000000000..1206aca4f6f7
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsProjectElementReference.java
@@ -0,0 +1,33 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+/**
+ * @author nik
+ */
+public class JpsProjectElementReference extends JpsElementBase implements JpsElementReference {
+ private final JpsModel myModel;
+
+ public JpsProjectElementReference(JpsModel model, JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(eventDispatcher, parent);
+ myModel = model;
+ }
+
+ @Override
+ public JpsProject resolve() {
+ return myModel.getProject();
+ }
+
+ @NotNull
+ @Override
+ public JpsProjectElementReference createCopy(@NotNull JpsModel model,
+ @NotNull JpsEventDispatcher eventDispatcher,
+ JpsParentElement parent) {
+ return new JpsProjectElementReference(model, eventDispatcher, parent);
+ }
+
+ @Override
+ public void applyChanges(@NotNull JpsProjectElementReference modified) {
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsProjectImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsProjectImpl.java
new file mode 100644
index 000000000000..006be0cfa53e
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsProjectImpl.java
@@ -0,0 +1,67 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.library.JpsLibraryType;
+import org.jetbrains.jps.model.library.impl.JpsLibraryImpl;
+import org.jetbrains.jps.model.library.impl.JpsLibraryKind;
+import org.jetbrains.jps.model.module.JpsModule;
+import org.jetbrains.jps.model.module.JpsModuleType;
+import org.jetbrains.jps.model.module.impl.JpsModuleImpl;
+import org.jetbrains.jps.model.module.impl.JpsModuleKind;
+
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public class JpsProjectImpl extends JpsCompositeElementBase implements JpsProject {
+ public JpsProjectImpl(JpsModel model, JpsEventDispatcher eventDispatcher) {
+ super(model, eventDispatcher, null);
+ myContainer.setChild(JpsModuleKind.MODULE_COLLECTION_KIND);
+ myContainer.setChild(JpsLibraryKind.LIBRARIES_COLLECTION_KIND);
+ }
+
+ public JpsProjectImpl(JpsProjectImpl original, JpsModel model, JpsEventDispatcher eventDispatcher) {
+ super(original, model, eventDispatcher, null);
+ }
+
+ @NotNull
+ @Override
+ public JpsModule addModule(@NotNull JpsModuleType> moduleType, @NotNull final String name) {
+ final JpsElementCollectionImpl collection = myContainer.getChild(JpsModuleKind.MODULE_COLLECTION_KIND);
+ return collection.addChild(new JpsModuleImpl(myModel, getEventDispatcher(), moduleType, name, collection));
+ }
+
+ @NotNull
+ @Override
+ public JpsLibrary addLibrary(@NotNull JpsLibraryType> libraryType, @NotNull final String name) {
+ final JpsElementCollectionImpl collection = myContainer.getChild(JpsLibraryKind.LIBRARIES_COLLECTION_KIND);
+ return collection.addChild(new JpsLibraryImpl(name, libraryType, myModel, getEventDispatcher(), collection));
+ }
+
+ @NotNull
+ @Override
+ public List extends JpsLibrary> getLibraries() {
+ return myContainer.getChild(JpsLibraryKind.LIBRARIES_COLLECTION_KIND).getElements();
+ }
+
+ @NotNull
+ @Override
+ public List extends JpsModule> getModules() {
+ return myContainer.getChild(JpsModuleKind.MODULE_COLLECTION_KIND).getElements();
+ }
+
+ @NotNull
+ @Override
+ public JpsElementReference createReference(JpsParentElement parent) {
+ return new JpsProjectElementReference(myModel, getEventDispatcher(), parent);
+ }
+
+ @NotNull
+ @Override
+ public JpsProjectImpl createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new JpsProjectImpl(this, model, eventDispatcher);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsTypedDataImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsTypedDataImpl.java
new file mode 100644
index 000000000000..4f3c47eb02d7
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsTypedDataImpl.java
@@ -0,0 +1,65 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jps.model.*;
+
+/**
+ * @author nik
+ */
+public class JpsTypedDataImpl extends JpsElementBase> {
+ private final T myType;
+ private JpsElementProperties myProperties;
+
+ public JpsTypedDataImpl(T type, JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(eventDispatcher, parent);
+ myType = type;
+ myProperties = type.createDefaultProperties();
+ }
+
+ public JpsTypedDataImpl(JpsTypedDataImpl original,
+ JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(original, eventDispatcher, parent);
+ myType = original.getType();
+ myProperties = createCopy(original.getType(), original.myProperties);
+ }
+
+ @Nullable
+ public P getProperties(JpsElementType
type) {
+ //noinspection unchecked
+ return myType.equals(type) ? (P)myProperties : null;
+ }
+
+ private static
P createCopy(final JpsElementType
type,
+ final JpsElementProperties properties) {
+ //noinspection unchecked
+ return type.createCopy((P)properties);
+ }
+
+ @NotNull
+ public T getType() {
+ return myType;
+ }
+
+ @NotNull
+ @Override
+ public JpsTypedDataImpl createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new JpsTypedDataImpl(this, eventDispatcher, parent);
+ }
+
+ @NotNull
+ public JpsElementProperties getProperties() {
+ return myProperties;
+ }
+
+ public void setProperties(@NotNull JpsElementProperties properties) {
+ if (!myProperties.equals(properties)) {
+ myProperties = properties;
+ getEventDispatcher().fireElementChanged(this);
+ }
+ }
+
+ public void applyChanges(@NotNull JpsTypedDataImpl data) {
+ setProperties(data.getProperties());
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsTypedDataKind.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsTypedDataKind.java
new file mode 100644
index 000000000000..bdb525eb5314
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsTypedDataKind.java
@@ -0,0 +1,10 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.jps.model.JpsElementKind;
+import org.jetbrains.jps.model.JpsElementType;
+
+/**
+ * @author nik
+ */
+public class JpsTypedDataKind extends JpsElementKind> {
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsUrlListImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsUrlListImpl.java
new file mode 100644
index 000000000000..5d1ac3ac2ee4
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/JpsUrlListImpl.java
@@ -0,0 +1,55 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public class JpsUrlListImpl extends JpsElementBase implements JpsUrlList {
+ private List myUrls = new ArrayList();
+
+ public JpsUrlListImpl(JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(eventDispatcher, parent);
+ }
+
+ public JpsUrlListImpl(JpsUrlListImpl list, JpsEventDispatcher dispatcher, JpsParentElement parent) {
+ super(list, dispatcher, parent);
+ myUrls.addAll(list.myUrls);
+ }
+
+ @NotNull
+ @Override
+ public JpsUrlListImpl createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new JpsUrlListImpl(this, eventDispatcher, parent);
+ }
+
+ @NotNull
+ @Override
+ public List getUrls() {
+ return myUrls;
+ }
+
+ @Override
+ public void addUrl(@NotNull String url) {
+ myUrls.add(url);
+ getEventDispatcher().fireElementChanged(this);
+ }
+
+ @Override
+ public void removeUrl(@NotNull String url) {
+ myUrls.remove(url);
+ getEventDispatcher().fireElementChanged(this);
+ }
+
+ public void applyChanges(@NotNull JpsUrlListImpl modified) {
+ if (!myUrls.equals(modified.myUrls)) {
+ myUrls.clear();
+ myUrls.addAll(modified.myUrls);
+ getEventDispatcher().fireElementChanged(this);
+ }
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/SimpleJpsElementImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/SimpleJpsElementImpl.java
new file mode 100644
index 000000000000..d60dd07afb8c
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/SimpleJpsElementImpl.java
@@ -0,0 +1,45 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+
+/**
+ * @author nik
+ */
+public class SimpleJpsElementImpl extends JpsElementBase> implements SimpleJpsElement {
+ private P myProperties;
+
+ public SimpleJpsElementImpl(JpsEventDispatcher eventDispatcher, P properties, JpsParentElement parent) {
+ super(eventDispatcher, parent);
+ myProperties = properties;
+ }
+
+ public SimpleJpsElementImpl(SimpleJpsElementImpl
original, JpsEventDispatcher dispatcher, JpsParentElement parent) {
+ super(original, dispatcher, parent);
+ }
+
+ @NotNull
+ @Override
+ public P getProperties() {
+ return myProperties;
+ }
+
+ @Override
+ public void setProperties(@NotNull P properties) {
+ if (!myProperties.equals(properties)) {
+ myProperties = properties;
+ getEventDispatcher().fireElementChanged(this);
+ }
+ }
+
+ @NotNull
+ @Override
+ public SimpleJpsElementImpl
createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new SimpleJpsElementImpl
(this, eventDispatcher, parent);
+ }
+
+ @Override
+ public void applyChanges(@NotNull SimpleJpsElementImpl
modified) {
+ setProperties(modified.getProperties());
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/impl/SimpleJpsElementKind.java b/jps/model-impl/src/org/jetbrains/jps/model/impl/SimpleJpsElementKind.java
new file mode 100644
index 000000000000..9e670f918f04
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/impl/SimpleJpsElementKind.java
@@ -0,0 +1,11 @@
+package org.jetbrains.jps.model.impl;
+
+import org.jetbrains.jps.model.JpsElementKind;
+import org.jetbrains.jps.model.JpsElementProperties;
+
+/**
+ * @author nik
+ */
+public class SimpleJpsElementKind
> extends
+ JpsElementKind> {
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleExtensionImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleExtensionImpl.java
new file mode 100644
index 000000000000..ff5dce87d4e1
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleExtensionImpl.java
@@ -0,0 +1,81 @@
+package org.jetbrains.jps.model.java.impl;
+
+import com.intellij.openapi.util.Comparing;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsEventDispatcher;
+import org.jetbrains.jps.model.JpsModel;
+import org.jetbrains.jps.model.JpsParentElement;
+import org.jetbrains.jps.model.impl.JpsElementBase;
+import org.jetbrains.jps.model.java.JavaModuleExtension;
+import org.jetbrains.jps.model.java.LanguageLevel;
+
+/**
+ * @author nik
+ */
+public class JavaModuleExtensionImpl extends JpsElementBase implements JavaModuleExtension {
+ private String myOutputUrl;
+ private String myTestOutputUrl;
+ private LanguageLevel myLanguageLevel;
+
+ public JavaModuleExtensionImpl(JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(eventDispatcher, parent);
+ }
+
+ public JavaModuleExtensionImpl(JavaModuleExtensionImpl original, JpsEventDispatcher dispatcher, JpsParentElement parent) {
+ super(original, dispatcher, parent);
+ myOutputUrl = original.myOutputUrl;
+ myTestOutputUrl = original.myTestOutputUrl;
+ myLanguageLevel = original.myLanguageLevel;
+ }
+
+ @NotNull
+ @Override
+ public JavaModuleExtensionImpl createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new JavaModuleExtensionImpl(this, eventDispatcher, parent);
+ }
+
+ @Override
+ public String getOutputUrl() {
+ return myOutputUrl;
+ }
+
+ @Override
+ public void setOutputUrl(String outputUrl) {
+ if (!Comparing.equal(myOutputUrl, outputUrl)) {
+ myOutputUrl = outputUrl;
+ getEventDispatcher().fireElementChanged(this);
+ }
+ }
+
+ @Override
+ public String getTestOutputUrl() {
+ return myTestOutputUrl;
+ }
+
+ @Override
+ public void setTestOutputUrl(String testOutputUrl) {
+ if (!Comparing.equal(myTestOutputUrl, testOutputUrl)) {
+ myTestOutputUrl = testOutputUrl;
+ getEventDispatcher().fireElementChanged(this);
+ }
+ }
+
+ @Override
+ public LanguageLevel getLanguageLevel() {
+ return myLanguageLevel;
+ }
+
+ @Override
+ public void setLanguageLevel(LanguageLevel languageLevel) {
+ if (!Comparing.equal(myLanguageLevel, languageLevel)) {
+ myLanguageLevel = languageLevel;
+ getEventDispatcher().fireElementChanged(this);
+ }
+ }
+
+ public void applyChanges(@NotNull JavaModuleExtensionImpl modified) {
+ setLanguageLevel(modified.myLanguageLevel);
+ setOutputUrl(modified.myOutputUrl);
+ setTestOutputUrl(modified.myTestOutputUrl);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleExtensionKind.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleExtensionKind.java
new file mode 100644
index 000000000000..0a62da133950
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleExtensionKind.java
@@ -0,0 +1,28 @@
+package org.jetbrains.jps.model.java.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+import org.jetbrains.jps.model.java.JavaModuleExtension;
+import org.jetbrains.jps.model.module.JpsModule;
+
+/**
+ * @author nik
+ */
+public class JavaModuleExtensionKind extends JpsElementKind implements JpsElementFactory {
+ public static final JavaModuleExtensionKind INSTANCE = new JavaModuleExtensionKind();
+
+ @NotNull
+ @Override
+ public JavaModuleExtensionImpl create(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new JavaModuleExtensionImpl(eventDispatcher, parent);
+ }
+
+ @NotNull
+ public static JavaModuleExtension getExtension(@NotNull JpsModule module) {
+ JavaModuleExtension child = module.getContainer().getChild(INSTANCE);
+ if (child == null) {
+ child = module.getContainer().setChild(INSTANCE);
+ }
+ return child;
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryImpl.java
new file mode 100644
index 000000000000..541d81b64667
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryImpl.java
@@ -0,0 +1,87 @@
+package org.jetbrains.jps.model.library.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+import org.jetbrains.jps.model.impl.*;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.library.JpsLibraryReference;
+import org.jetbrains.jps.model.library.JpsLibraryRootType;
+import org.jetbrains.jps.model.library.JpsLibraryType;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public class JpsLibraryImpl extends JpsNamedCompositeElementBase implements JpsLibrary {
+ private static final JpsElementCollectionKind LIBRARY_ROOTS_COLLECTION = new JpsElementCollectionKind(JpsLibraryRootKind.INSTANCE);
+ private static final JpsTypedDataKind> TYPED_DATA_KIND = new JpsTypedDataKind>();
+
+ public JpsLibraryImpl(@NotNull String name, @NotNull JpsLibraryType> type, @NotNull JpsModel model,
+ @NotNull JpsEventDispatcher eventDispatcher, JpsElementCollection parent) {
+ super(model, eventDispatcher, name, parent);
+ myContainer.setChild(TYPED_DATA_KIND, new JpsTypedDataImpl>(type, eventDispatcher, this));
+ myContainer.setChild(LIBRARY_ROOTS_COLLECTION);
+ }
+
+ public JpsLibraryImpl(@NotNull JpsLibraryImpl original, JpsModel model, JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(original, model, eventDispatcher, parent);
+ }
+
+ @NotNull
+ @Override
+ public List getUrls(@NotNull JpsLibraryRootType rootType) {
+ final List urls = new ArrayList();
+ for (JpsLibraryRootImpl root : getRootsCollection().getElements()) {
+ if (root.getRootType().equals(rootType)) {
+ urls.add(root.getUrl());
+ }
+ }
+ return urls;
+ }
+
+ @Override
+ public void addUrl(@NotNull final String url, @NotNull final JpsLibraryRootType rootType) {
+ getRootsCollection().addChild(new JpsLibraryRootImpl(getEventDispatcher(), url, rootType, this));
+ }
+
+ private JpsElementCollectionImpl getRootsCollection() {
+ return myContainer.getChild(LIBRARY_ROOTS_COLLECTION);
+ }
+
+ @Override
+ public void removeUrl(@NotNull final String url, @NotNull final JpsLibraryRootType rootType) {
+ final JpsElementCollectionImpl rootsCollection = getRootsCollection();
+ for (JpsLibraryRootImpl root : rootsCollection.getElements()) {
+ if (root.getUrl().equals(url) && root.getRootType().equals(rootType)) {
+ rootsCollection.removeChild(root);
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void delete() {
+ getParent().removeChild(this);
+ }
+
+ public JpsElementCollectionImpl getParent() {
+ //noinspection unchecked
+ return (JpsElementCollectionImpl)myParent;
+ }
+
+ @NotNull
+ @Override
+ public JpsLibraryImpl createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new JpsLibraryImpl(this, model, eventDispatcher, parent);
+ }
+
+ @NotNull
+ @Override
+ public JpsLibraryReference createReference(JpsParentElement parent) {
+ //noinspection unchecked
+ final JpsElementReference parentReference = ((JpsReferenceableElement)getParent().getParent()).createReference(parent);
+ return new JpsLibraryReferenceImpl(myModel, getEventDispatcher(), getName(), parentReference, parent);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryKind.java b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryKind.java
new file mode 100644
index 000000000000..834ada9984fb
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryKind.java
@@ -0,0 +1,28 @@
+package org.jetbrains.jps.model.library.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElementKind;
+import org.jetbrains.jps.model.JpsEventDispatcher;
+import org.jetbrains.jps.model.impl.JpsElementCollectionKind;
+import org.jetbrains.jps.model.library.JpsLibraryListener;
+
+/**
+ * @author nik
+ */
+public class JpsLibraryKind extends JpsElementKind {
+ public static final JpsLibraryKind INSTANCE = new JpsLibraryKind();
+ public static final JpsElementCollectionKind LIBRARIES_COLLECTION_KIND = new JpsElementCollectionKind(INSTANCE);
+
+ private JpsLibraryKind() {
+ }
+
+ @Override
+ public void fireElementAdded(@NotNull JpsEventDispatcher dispatcher, @NotNull JpsLibraryImpl element) {
+ dispatcher.getPublisher(JpsLibraryListener.class).libraryAdded(element);
+ }
+
+ @Override
+ public void fireElementRemoved(@NotNull JpsEventDispatcher dispatcher, @NotNull JpsLibraryImpl element) {
+ dispatcher.getPublisher(JpsLibraryListener.class).libraryRemoved(element);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryReferenceImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryReferenceImpl.java
new file mode 100644
index 000000000000..c78e4bdd8c0c
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryReferenceImpl.java
@@ -0,0 +1,35 @@
+package org.jetbrains.jps.model.library.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+import org.jetbrains.jps.model.impl.JpsNamedElementReferenceBase;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.library.JpsLibraryReference;
+
+/**
+ * @author nik
+ */
+public class JpsLibraryReferenceImpl extends JpsNamedElementReferenceBase implements JpsLibraryReference {
+ public JpsLibraryReferenceImpl(JpsModel model, JpsEventDispatcher eventDispatcher, String elementName, JpsElementReference extends JpsCompositeElement> parentReference,
+ JpsParentElement parent) {
+ super(model, eventDispatcher, JpsLibraryKind.LIBRARIES_COLLECTION_KIND, elementName, parentReference, parent);
+ }
+
+ public JpsLibraryReferenceImpl(JpsLibraryReferenceImpl original, JpsModel model, JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(original, model, eventDispatcher, parent);
+ }
+
+ @NotNull
+ @Override
+ public String getLibraryName() {
+ return myElementName;
+ }
+
+ @NotNull
+ @Override
+ public JpsLibraryReferenceImpl createCopy(@NotNull JpsModel model,
+ @NotNull JpsEventDispatcher eventDispatcher,
+ JpsParentElement parent) {
+ return new JpsLibraryReferenceImpl(this, model, eventDispatcher, parent);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryRootImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryRootImpl.java
new file mode 100644
index 000000000000..6279e3adfa72
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryRootImpl.java
@@ -0,0 +1,56 @@
+package org.jetbrains.jps.model.library.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsEventDispatcher;
+import org.jetbrains.jps.model.JpsModel;
+import org.jetbrains.jps.model.JpsParentElement;
+import org.jetbrains.jps.model.impl.JpsElementBase;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.library.JpsLibraryRoot;
+import org.jetbrains.jps.model.library.JpsLibraryRootType;
+
+/**
+ * @author nik
+ */
+public class JpsLibraryRootImpl extends JpsElementBase implements JpsLibraryRoot {
+ private final String myUrl;
+ private final JpsLibraryRootType myRootType;
+
+ public JpsLibraryRootImpl(JpsEventDispatcher eventDispatcher, @NotNull String url, @NotNull JpsLibraryRootType rootType, @NotNull JpsParentElement parent) {
+ super(eventDispatcher, parent);
+ myUrl = url;
+ myRootType = rootType;
+ }
+
+ public JpsLibraryRootImpl(JpsLibraryRootImpl original, JpsEventDispatcher dispatcher, JpsParentElement parent) {
+ super(original, dispatcher, parent);
+ myUrl = original.myUrl;
+ myRootType = original.myRootType;
+ }
+
+ @NotNull
+ @Override
+ public JpsLibraryRootType getRootType() {
+ return myRootType;
+ }
+
+ @NotNull
+ public String getUrl() {
+ return myUrl;
+ }
+
+ @NotNull
+ @Override
+ public JpsLibraryRootImpl createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new JpsLibraryRootImpl(this, eventDispatcher, parent);
+ }
+
+ public void applyChanges(@NotNull JpsLibraryRootImpl modified) {
+ }
+
+ @Override
+ @NotNull
+ public JpsLibrary getLibrary() {
+ return (JpsLibrary)myParent;
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryRootKind.java b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryRootKind.java
new file mode 100644
index 000000000000..4043b76287ce
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryRootKind.java
@@ -0,0 +1,23 @@
+package org.jetbrains.jps.model.library.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElementKind;
+import org.jetbrains.jps.model.JpsEventDispatcher;
+import org.jetbrains.jps.model.library.JpsLibraryRootListener;
+
+/**
+ * @author nik
+ */
+public class JpsLibraryRootKind extends JpsElementKind {
+ public static final JpsLibraryRootKind INSTANCE = new JpsLibraryRootKind();
+
+ @Override
+ public void fireElementAdded(@NotNull JpsEventDispatcher dispatcher, @NotNull JpsLibraryRootImpl element) {
+ dispatcher.getPublisher(JpsLibraryRootListener.class).rootAdded(element);
+ }
+
+ @Override
+ public void fireElementRemoved(@NotNull JpsEventDispatcher dispatcher, @NotNull JpsLibraryRootImpl element) {
+ dispatcher.getPublisher(JpsLibraryRootListener.class).rootRemoved(element);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/DependenciesListImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/DependenciesListImpl.java
new file mode 100644
index 000000000000..8afc76bbe105
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/DependenciesListImpl.java
@@ -0,0 +1,58 @@
+package org.jetbrains.jps.model.module.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElementKind;
+import org.jetbrains.jps.model.JpsEventDispatcher;
+import org.jetbrains.jps.model.JpsModel;
+import org.jetbrains.jps.model.JpsParentElement;
+import org.jetbrains.jps.model.impl.JpsCompositeElementBase;
+import org.jetbrains.jps.model.impl.JpsElementCollectionKind;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.module.*;
+
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public class DependenciesListImpl extends JpsCompositeElementBase implements DependenciesList {
+ public static final JpsElementKind> DEPENDENCY_ELEMENT_KIND = new JpsElementKind>();
+ public static final JpsElementCollectionKind> DEPENDENCY_COLLECTION_KIND = new JpsElementCollectionKind>(DEPENDENCY_ELEMENT_KIND);
+
+ public DependenciesListImpl(JpsModel model, JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(model, eventDispatcher, parent);
+ myContainer.setChild(DEPENDENCY_COLLECTION_KIND);
+ }
+
+ public DependenciesListImpl(DependenciesListImpl original, JpsModel model, JpsEventDispatcher dispatcher, JpsParentElement parent) {
+ super(original, model, dispatcher, parent);
+ }
+
+ @Override
+ @NotNull
+ public List extends JpsDependencyElement> getDependencies() {
+ return myContainer.getChild(DEPENDENCY_COLLECTION_KIND).getElements();
+ }
+
+ @Override
+ @NotNull
+ public JpsModuleDependency addModuleDependency(@NotNull JpsModule module) {
+ final JpsModuleDependencyImpl dependency = new JpsModuleDependencyImpl(myModel, getEventDispatcher(), module, this);
+ myContainer.getChild(DEPENDENCY_COLLECTION_KIND).addChild(dependency);
+ return dependency;
+ }
+
+ @Override
+ @NotNull
+ public JpsLibraryDependency addLibraryDependency(@NotNull JpsLibrary libraryElement) {
+ JpsLibraryDependencyImpl dependency = new JpsLibraryDependencyImpl(myModel, getEventDispatcher(), libraryElement, this);
+ myContainer.getChild(DEPENDENCY_COLLECTION_KIND).addChild(dependency);
+ return dependency;
+ }
+
+ @NotNull
+ @Override
+ public DependenciesListImpl createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new DependenciesListImpl(this, model, eventDispatcher, parent);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsDependencyElementBase.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsDependencyElementBase.java
new file mode 100644
index 000000000000..9376f5154d77
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsDependencyElementBase.java
@@ -0,0 +1,21 @@
+package org.jetbrains.jps.model.module.impl;
+
+import org.jetbrains.jps.model.JpsEventDispatcher;
+import org.jetbrains.jps.model.JpsModel;
+import org.jetbrains.jps.model.JpsParentElement;
+import org.jetbrains.jps.model.impl.JpsCompositeElementBase;
+import org.jetbrains.jps.model.module.JpsDependencyElement;
+
+/**
+ * @author nik
+ */
+public abstract class JpsDependencyElementBase> extends JpsCompositeElementBase implements JpsDependencyElement {
+ protected JpsDependencyElementBase(JpsModel model, JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(model, eventDispatcher, parent);
+ }
+
+ protected JpsDependencyElementBase(JpsDependencyElementBase original, JpsModel model, JpsEventDispatcher dispatcher, JpsParentElement parent) {
+ super(original, model, dispatcher, parent);
+ }
+
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsLibraryDependencyImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsLibraryDependencyImpl.java
new file mode 100644
index 000000000000..d1557b2824b4
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsLibraryDependencyImpl.java
@@ -0,0 +1,37 @@
+package org.jetbrains.jps.model.module.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.library.JpsLibraryReference;
+import org.jetbrains.jps.model.module.JpsLibraryDependency;
+
+/**
+ * @author nik
+ */
+public class JpsLibraryDependencyImpl extends JpsDependencyElementBase implements JpsLibraryDependency {
+ public static final JpsElementKind LIBRARY_REFERENCE_KIND = new JpsElementKind();
+
+ public JpsLibraryDependencyImpl(JpsModel model, JpsEventDispatcher eventDispatcher, JpsLibrary library, JpsParentElement parent) {
+ super(model, eventDispatcher, parent);
+ myContainer.setChild(LIBRARY_REFERENCE_KIND, library.createReference(parent));
+ }
+
+ public JpsLibraryDependencyImpl(JpsLibraryDependencyImpl original, @NotNull JpsModel model, JpsEventDispatcher dispatcher, JpsParentElement parent) {
+ super(original, model, dispatcher, parent);
+ }
+
+ @NotNull
+ @Override
+ public JpsLibraryReference getLibraryReference() {
+ return myContainer.getChild(LIBRARY_REFERENCE_KIND);
+ }
+
+ @NotNull
+ @Override
+ public JpsLibraryDependencyImpl createCopy(@NotNull JpsModel model,
+ @NotNull JpsEventDispatcher eventDispatcher,
+ JpsParentElement parent) {
+ return new JpsLibraryDependencyImpl(this, model, eventDispatcher, parent);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleDependencyImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleDependencyImpl.java
new file mode 100644
index 000000000000..dfae14b35443
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleDependencyImpl.java
@@ -0,0 +1,37 @@
+package org.jetbrains.jps.model.module.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+import org.jetbrains.jps.model.module.JpsModule;
+import org.jetbrains.jps.model.module.JpsModuleDependency;
+import org.jetbrains.jps.model.module.JpsModuleReference;
+
+/**
+ * @author nik
+ */
+public class JpsModuleDependencyImpl extends JpsDependencyElementBase implements JpsModuleDependency {
+ private static final JpsElementKind MODULE_REFERENCE_KIND = new JpsElementKind();
+
+ public JpsModuleDependencyImpl(JpsModel model, JpsEventDispatcher eventDispatcher, JpsModule module, JpsParentElement parent) {
+ super(model, eventDispatcher, parent);
+ myContainer.setChild(MODULE_REFERENCE_KIND, module.createReference(this));
+ }
+
+ public JpsModuleDependencyImpl(JpsModuleDependencyImpl original, JpsModel model, JpsEventDispatcher dispatcher, JpsParentElement parent) {
+ super(original, model, dispatcher, parent);
+ }
+
+ @NotNull
+ @Override
+ public JpsModuleReference getModuleReference() {
+ return myContainer.getChild(MODULE_REFERENCE_KIND);
+ }
+
+ @NotNull
+ @Override
+ public JpsModuleDependencyImpl createCopy(@NotNull JpsModel model,
+ @NotNull JpsEventDispatcher eventDispatcher,
+ JpsParentElement parent) {
+ return new JpsModuleDependencyImpl(this, model, eventDispatcher, parent);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleImpl.java
new file mode 100644
index 000000000000..7dacd91103a6
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleImpl.java
@@ -0,0 +1,100 @@
+package org.jetbrains.jps.model.module.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+import org.jetbrains.jps.model.impl.*;
+import org.jetbrains.jps.model.module.*;
+
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public class JpsModuleImpl extends JpsNamedCompositeElementBase implements JpsModule {
+ private static final JpsTypedDataKind TYPED_DATA_KIND = new JpsTypedDataKind();
+ private static final JpsElementKind CONTENT_ROOTS_KIND = new JpsElementKind();
+ private static final JpsElementKind EXCLUDED_ROOTS_KIND = new JpsElementKind();
+ public static final JpsElementKind DEPENDENCIES_LIST_KIND = new JpsElementKind();
+
+ public JpsModuleImpl(JpsModel model, JpsEventDispatcher eventDispatcher, JpsModuleType type, @NotNull String name, JpsElementCollectionImpl parent) {
+ super(model, eventDispatcher, name, parent);
+ myContainer.setChild(TYPED_DATA_KIND, new JpsTypedDataImpl(type, eventDispatcher, this));
+ myContainer.setChild(CONTENT_ROOTS_KIND, new JpsUrlListImpl(eventDispatcher, parent));
+ myContainer.setChild(EXCLUDED_ROOTS_KIND, new JpsUrlListImpl(eventDispatcher, parent));
+ myContainer.setChild(DEPENDENCIES_LIST_KIND, new DependenciesListImpl(model, eventDispatcher, this));
+ myContainer.setChild(JpsModuleSourceRootKind.ROOT_COLLECTION_KIND);
+ }
+
+ public JpsModuleImpl(JpsModuleImpl original, JpsEventDispatcher eventDispatcher, JpsModel model, JpsParentElement parent) {
+ super(original, model, eventDispatcher, parent);
+ }
+
+ @NotNull
+ @Override
+ public JpsModuleImpl createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new JpsModuleImpl(this, eventDispatcher, model, parent);
+ }
+
+ @NotNull
+ @Override
+ public JpsUrlList getContentRootsList() {
+ return myContainer.getChild(CONTENT_ROOTS_KIND);
+ }
+
+ @NotNull
+ public JpsUrlList getExcludeRootsList() {
+ return myContainer.getChild(EXCLUDED_ROOTS_KIND);
+ }
+
+ @NotNull
+ @Override
+ public List extends JpsModuleSourceRootImpl> getSourceRoots() {
+ return myContainer.getChild(JpsModuleSourceRootKind.ROOT_COLLECTION_KIND).getElements();
+ }
+
+ @NotNull
+ @Override
+ public JpsModuleSourceRoot addSourceRoot(@NotNull JpsModuleSourceRootType
rootType,
+ @NotNull String url) {
+ return addSourceRoot(rootType, url, rootType.createDefaultProperties());
+ }
+
+ @NotNull
+ @Override
+ public
JpsModuleSourceRoot addSourceRoot(@NotNull JpsModuleSourceRootType
rootType,
+ @NotNull String url,
+ @NotNull P properties) {
+ final JpsModuleSourceRootImpl root = new JpsModuleSourceRootImpl(myModel, getEventDispatcher(), url, rootType, this);
+ myContainer.getChild(JpsModuleSourceRootKind.ROOT_COLLECTION_KIND).addChild(root);
+ root.setProperties(rootType, properties);
+ return root;
+ }
+
+ @Override
+ public void removeSourceRoot(@NotNull JpsModuleSourceRootType rootType, @NotNull String url) {
+ final JpsElementCollectionImpl roots = myContainer.getChild(JpsModuleSourceRootKind.ROOT_COLLECTION_KIND);
+ for (JpsModuleSourceRootImpl root : roots.getElements()) {
+ if (root.getRootType().equals(rootType) && root.getUrl().equals(url)) {
+ roots.removeChild(root);
+ break;
+ }
+ }
+ }
+
+ @Override
+ public DependenciesList getDependenciesList() {
+ return myContainer.getChild(DEPENDENCIES_LIST_KIND);
+ }
+
+ @Override
+ public void delete() {
+ //noinspection unchecked
+ ((JpsElementCollectionImpl)myParent).removeChild(this);
+ }
+
+ @NotNull
+ @Override
+ public JpsModuleReference createReference(JpsParentElement parent) {
+ return new JpsModuleReferenceImpl(myModel, getName(), getEventDispatcher(), parent);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleKind.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleKind.java
new file mode 100644
index 000000000000..74621d367f0c
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleKind.java
@@ -0,0 +1,25 @@
+package org.jetbrains.jps.model.module.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElementKind;
+import org.jetbrains.jps.model.JpsEventDispatcher;
+import org.jetbrains.jps.model.impl.JpsElementCollectionKind;
+import org.jetbrains.jps.model.module.JpsModuleListener;
+
+/**
+ * @author nik
+ */
+public class JpsModuleKind extends JpsElementKind {
+ public static final JpsElementKind INSTANCE = new JpsModuleKind();
+ public static final JpsElementCollectionKind MODULE_COLLECTION_KIND = new JpsElementCollectionKind(INSTANCE);
+
+ @Override
+ public void fireElementAdded(@NotNull JpsEventDispatcher dispatcher, @NotNull JpsModuleImpl element) {
+ dispatcher.getPublisher(JpsModuleListener.class).moduleAdded(element);
+ }
+
+ @Override
+ public void fireElementRemoved(@NotNull JpsEventDispatcher dispatcher, @NotNull JpsModuleImpl element) {
+ dispatcher.getPublisher(JpsModuleListener.class).moduleRemoved(element);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleReferenceImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleReferenceImpl.java
new file mode 100644
index 000000000000..0d9d6a3607fa
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleReferenceImpl.java
@@ -0,0 +1,34 @@
+package org.jetbrains.jps.model.module.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsCompositeElement;
+import org.jetbrains.jps.model.JpsEventDispatcher;
+import org.jetbrains.jps.model.JpsModel;
+import org.jetbrains.jps.model.JpsParentElement;
+import org.jetbrains.jps.model.impl.JpsNamedElementReferenceBase;
+import org.jetbrains.jps.model.impl.JpsProjectElementReference;
+import org.jetbrains.jps.model.module.JpsModule;
+import org.jetbrains.jps.model.module.JpsModuleReference;
+
+/**
+ * @author nik
+ */
+public class JpsModuleReferenceImpl extends JpsNamedElementReferenceBase implements JpsModuleReference {
+ public JpsModuleReferenceImpl(JpsModel model, String elementName, JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ super(model, eventDispatcher, JpsModuleKind.MODULE_COLLECTION_KIND, elementName, new JpsProjectElementReference(model, eventDispatcher, parent), parent);
+ }
+
+ @NotNull
+ @Override
+ public JpsModuleReferenceImpl createCopy(@NotNull JpsModel model,
+ @NotNull JpsEventDispatcher eventDispatcher,
+ JpsParentElement parent) {
+ return new JpsModuleReferenceImpl(model, myElementName, eventDispatcher, parent);
+ }
+
+ @NotNull
+ @Override
+ public String getModuleName() {
+ return myElementName;
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleSourceRootImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleSourceRootImpl.java
new file mode 100644
index 000000000000..76d8aaba9d15
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleSourceRootImpl.java
@@ -0,0 +1,57 @@
+package org.jetbrains.jps.model.module.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.*;
+import org.jetbrains.jps.model.impl.JpsCompositeElementBase;
+import org.jetbrains.jps.model.impl.JpsTypedDataImpl;
+import org.jetbrains.jps.model.impl.JpsTypedDataKind;
+import org.jetbrains.jps.model.module.JpsModuleSourceRoot;
+import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
+
+/**
+ * @author nik
+ */
+public class JpsModuleSourceRootImpl extends JpsCompositeElementBase implements JpsModuleSourceRoot {
+ private static final JpsTypedDataKind TYPED_DATA_KIND = new JpsTypedDataKind();
+ private String myUrl;
+
+ public JpsModuleSourceRootImpl(JpsModel model, JpsEventDispatcher eventDispatcher,
+ String url,
+ JpsModuleSourceRootType type, JpsParentElement parent) {
+ super(model, eventDispatcher, parent);
+ myContainer.setChild(TYPED_DATA_KIND, new JpsTypedDataImpl(type, eventDispatcher, this));
+ myUrl = url;
+ }
+
+ public JpsModuleSourceRootImpl(JpsModuleSourceRootImpl original, JpsModel model, JpsEventDispatcher dispatcher, JpsParentElement parent) {
+ super(original, model, dispatcher, parent);
+ myUrl = original.myUrl;
+ }
+
+ @Override
+ public P getProperties(@NotNull JpsModuleSourceRootType
type) {
+ return myContainer.getChild(TYPED_DATA_KIND).getProperties(type);
+ }
+
+ @Override
+ public
void setProperties(JpsModuleSourceRootType
type, P properties) {
+ myContainer.getChild(TYPED_DATA_KIND).setProperties(properties);
+ }
+
+ @NotNull
+ @Override
+ public JpsModuleSourceRootType> getRootType() {
+ return myContainer.getChild(TYPED_DATA_KIND).getType();
+ }
+
+ @NotNull
+ public String getUrl() {
+ return myUrl;
+ }
+
+ @NotNull
+ @Override
+ public JpsModuleSourceRootImpl createCopy(@NotNull JpsModel model, @NotNull JpsEventDispatcher eventDispatcher, JpsParentElement parent) {
+ return new JpsModuleSourceRootImpl(this, model, eventDispatcher, parent);
+ }
+}
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleSourceRootKind.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleSourceRootKind.java
new file mode 100644
index 000000000000..70e25abff2dc
--- /dev/null
+++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleSourceRootKind.java
@@ -0,0 +1,25 @@
+package org.jetbrains.jps.model.module.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElementKind;
+import org.jetbrains.jps.model.JpsEventDispatcher;
+import org.jetbrains.jps.model.impl.JpsElementCollectionKind;
+import org.jetbrains.jps.model.module.JpsModuleSourceRootListener;
+
+/**
+ * @author nik
+ */
+public class JpsModuleSourceRootKind extends JpsElementKind {
+ public static final JpsModuleSourceRootKind INSTANCE = new JpsModuleSourceRootKind();
+ public static final JpsElementCollectionKind ROOT_COLLECTION_KIND = new JpsElementCollectionKind(INSTANCE);
+
+ @Override
+ public void fireElementAdded(@NotNull JpsEventDispatcher dispatcher, @NotNull JpsModuleSourceRootImpl element) {
+ dispatcher.getPublisher(JpsModuleSourceRootListener.class).sourceRootAdded(element);
+ }
+
+ @Override
+ public void fireElementRemoved(@NotNull JpsEventDispatcher dispatcher, @NotNull JpsModuleSourceRootImpl element) {
+ dispatcher.getPublisher(JpsModuleSourceRootListener.class).sourceRootRemoved(element);
+ }
+}
diff --git a/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsJavaExtensionTest.java b/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsJavaExtensionTest.java
new file mode 100644
index 000000000000..cc6562a97c11
--- /dev/null
+++ b/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsJavaExtensionTest.java
@@ -0,0 +1,16 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.jps.model.java.JpsJavaModuleType;
+import org.jetbrains.jps.model.java.impl.JavaModuleExtensionKind;
+import org.jetbrains.jps.model.module.JpsModule;
+
+/**
+ * @author nik
+ */
+public class JpsJavaExtensionTest extends JpsModelTestCase {
+ public void test() {
+ final JpsModule module = myModel.getProject().addModule(JpsJavaModuleType.INSTANCE, "m");
+ JavaModuleExtensionKind.getExtension(module).setOutputUrl("file://path");
+ assertEquals("file://path", JavaModuleExtensionKind.getExtension(module).getOutputUrl());
+ }
+}
diff --git a/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsLibraryTest.java b/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsLibraryTest.java
new file mode 100644
index 000000000000..f437c6d7e192
--- /dev/null
+++ b/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsLibraryTest.java
@@ -0,0 +1,48 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.jps.model.impl.JpsProjectImpl;
+import org.jetbrains.jps.model.java.JpsJavaLibraryType;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.library.JpsLibraryReference;
+import org.jetbrains.jps.model.library.JpsLibraryRootType;
+import org.jetbrains.jps.model.library.impl.JpsLibraryReferenceImpl;
+
+/**
+ * @author nik
+ */
+public class JpsLibraryTest extends JpsModelTestCase {
+ public void testAddRoot() {
+ final JpsLibrary library = myModel.getProject().addLibrary(JpsJavaLibraryType.INSTANCE, "a");
+ library.addUrl("file://my-url", JpsLibraryRootType.COMPILED);
+ assertEquals("file://my-url", assertOneElement(library.getUrls(JpsLibraryRootType.COMPILED)));
+ }
+
+ public void testModifiableCopy() {
+ myModel.getProject().addLibrary(JpsJavaLibraryType.INSTANCE, "a");
+
+ final JpsModel modifiableModel = myModel.createModifiableModel(new TestJpsEventDispatcher());
+ final JpsLibrary modifiable = assertOneElement(modifiableModel.getProject().getLibraries());
+ modifiable.addUrl("file://my-url", JpsLibraryRootType.COMPILED);
+ modifiableModel.commit();
+
+ final JpsLibrary library = assertOneElement(myModel.getProject().getLibraries());
+ assertEquals("file://my-url", assertOneElement(library.getUrls(JpsLibraryRootType.COMPILED)));
+ }
+
+ public void testCreateReferenceByLibrary() {
+ final JpsLibrary library = myModel.getProject().addLibrary(JpsJavaLibraryType.INSTANCE, "l");
+ final JpsLibraryReference reference = library.createReference(myModel.getProject());
+ assertEquals("l", reference.getLibraryName());
+ assertSame(library, reference.resolve());
+ }
+
+ public void testCreateReferenceByName() {
+ final JpsProjectImpl project = myModel.getProject();
+ JpsLibraryReference reference = new JpsLibraryReferenceImpl(myModel, myDispatcher, "l", myModel.getProject().createReference(project), project);
+ assertEquals("l", reference.getLibraryName());
+ assertNull(reference.resolve());
+
+ final JpsLibrary library = myModel.getProject().addLibrary(JpsJavaLibraryType.INSTANCE, "l");
+ assertSame(library, reference.resolve());
+ }
+}
diff --git a/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsModelTestCase.java b/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsModelTestCase.java
new file mode 100644
index 000000000000..fb3b425b68c2
--- /dev/null
+++ b/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsModelTestCase.java
@@ -0,0 +1,18 @@
+package org.jetbrains.jps.model;
+
+import com.intellij.testFramework.UsefulTestCase;
+import org.jetbrains.jps.model.impl.JpsModelImpl;
+
+/**
+ * @author nik
+ */
+public abstract class JpsModelTestCase extends UsefulTestCase {
+ protected JpsModelImpl myModel;
+ protected TestJpsEventDispatcher myDispatcher;
+
+ public void setUp() throws Exception {
+ super.setUp();
+ myDispatcher = new TestJpsEventDispatcher();
+ myModel = new JpsModelImpl(myDispatcher);
+ }
+}
diff --git a/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsModuleTest.java b/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsModuleTest.java
new file mode 100644
index 000000000000..07b12d0e5b57
--- /dev/null
+++ b/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsModuleTest.java
@@ -0,0 +1,83 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.jps.model.impl.JpsProjectImpl;
+import org.jetbrains.jps.model.java.JpsJavaLibraryType;
+import org.jetbrains.jps.model.java.JpsJavaModuleType;
+import org.jetbrains.jps.model.java.JavaSourceRootProperties;
+import org.jetbrains.jps.model.java.JavaSourceRootType;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.module.*;
+import org.jetbrains.jps.model.module.impl.JpsModuleReferenceImpl;
+
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public class JpsModuleTest extends JpsModelTestCase {
+ public void testAddSourceRoot() {
+ final JpsModule module = myModel.getProject().addModule(JpsJavaModuleType.INSTANCE, "m");
+ final JpsModuleSourceRoot sourceRoot = module.addSourceRoot(JavaSourceRootType.SOURCE, "file://url", new JavaSourceRootProperties("com.xxx"));
+
+ assertSameElements(myDispatcher.retrieveAdded(JpsModule.class), module);
+ assertSameElements(myDispatcher.retrieveAdded(JpsModuleSourceRoot.class), sourceRoot);
+
+ final JpsModuleSourceRoot root = assertOneElement(module.getSourceRoots());
+ assertEquals("file://url", root.getUrl());
+ final JavaSourceRootProperties properties = root.getProperties(JavaSourceRootType.SOURCE);
+ assertNotNull(properties);
+ assertEquals("com.xxx", properties.getPackagePrefix());
+ }
+
+ public void testModifiableModel() {
+ final JpsModule module = myModel.getProject().addModule(JpsJavaModuleType.INSTANCE, "m");
+ final JpsModuleSourceRoot root0 = module.addSourceRoot(JavaSourceRootType.SOURCE, "url1");
+ myDispatcher.clear();
+
+ final JpsModel modifiableModel = myModel.createModifiableModel(new TestJpsEventDispatcher());
+ final JpsModule modifiableModule = assertOneElement(modifiableModel.getProject().getModules());
+ modifiableModule.addSourceRoot(JavaSourceRootType.TEST_SOURCE, "url2");
+ modifiableModel.commit();
+
+ assertEmpty(myDispatcher.retrieveAdded(JpsModule.class));
+ assertEmpty(myDispatcher.retrieveRemoved(JpsModule.class));
+
+ final List extends JpsModuleSourceRoot> roots = module.getSourceRoots();
+ assertEquals(2, roots.size());
+ assertSame(root0, roots.get(0));
+ final JpsModuleSourceRoot root1 = roots.get(1);
+ assertEquals("url2", root1.getUrl());
+ assertOrderedEquals(myDispatcher.retrieveAdded(JpsModuleSourceRoot.class), root1);
+ assertEmpty(myDispatcher.retrieveChanged(JpsModuleSourceRoot.class));
+ }
+
+ public void testAddDependency() {
+ final JpsModule module = myModel.getProject().addModule(JpsJavaModuleType.INSTANCE, "m");
+ final JpsLibrary library = myModel.getProject().addLibrary(JpsJavaLibraryType.INSTANCE, "l");
+ final JpsModule dep = myModel.getProject().addModule(JpsJavaModuleType.INSTANCE, "dep");
+ module.getDependenciesList().addLibraryDependency(library);
+ module.getDependenciesList().addModuleDependency(dep);
+
+ final List extends JpsDependencyElement> dependencies = module.getDependenciesList().getDependencies();
+ assertEquals(2, dependencies.size());
+ assertSame(library, assertInstanceOf(dependencies.get(0), JpsLibraryDependency.class).getLibraryReference().resolve());
+ assertSame(dep, assertInstanceOf(dependencies.get(1), JpsModuleDependency.class).getModuleReference().resolve());
+ }
+
+ public void testCreateReferenceByModule() {
+ final JpsModule module = myModel.getProject().addModule(JpsJavaModuleType.INSTANCE, "m");
+ final JpsModuleReference reference = module.createReference(myModel.getProject());
+ assertEquals("m", reference.getModuleName());
+ assertSame(module, reference.resolve());
+ }
+
+ public void testCreateReferenceByName() {
+ final JpsProjectImpl project = myModel.getProject();
+ final JpsModuleReference reference = new JpsModuleReferenceImpl(myModel, "m", myDispatcher, project);
+ assertEquals("m", reference.getModuleName());
+ assertNull(reference.resolve());
+
+ final JpsModule module = project.addModule(JpsJavaModuleType.INSTANCE, "m");
+ assertSame(module, reference.resolve());
+ }
+}
diff --git a/jps/model-impl/testSrc/org/jetbrains/jps/model/TestJpsEventDispatcher.java b/jps/model-impl/testSrc/org/jetbrains/jps/model/TestJpsEventDispatcher.java
new file mode 100644
index 000000000000..5da03b935dc3
--- /dev/null
+++ b/jps/model-impl/testSrc/org/jetbrains/jps/model/TestJpsEventDispatcher.java
@@ -0,0 +1,70 @@
+package org.jetbrains.jps.model;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.impl.JpsEventDispatcherBase;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author nik
+ */
+class TestJpsEventDispatcher extends JpsEventDispatcherBase implements JpsEventDispatcher {
+ private List myAdded = new ArrayList();
+ private List myRemoved = new ArrayList();
+ private List myChanged = new ArrayList();
+
+ @Override
+ public void fireElementAdded(@NotNull T element, @NotNull JpsElementKind kind) {
+ super.fireElementAdded(element, kind);
+ myAdded.add(element);
+ }
+
+ @Override
+ public void fireElementRemoved(@NotNull T element, @NotNull JpsElementKind kind) {
+ super.fireElementRemoved(element, kind);
+ myRemoved.add(element);
+ }
+
+ @Override
+ public void fireElementChanged(@NotNull JpsElement element) {
+ myChanged.add(element);
+ }
+
+ @Override
+ public void fireElementRenamed(@NotNull JpsNamedElement element, @NotNull String oldName, @NotNull String newName) {
+ }
+
+ public List retrieveAdded(Class type) {
+ return retrieve(type, myAdded);
+ }
+
+ public List retrieveRemoved(Class type) {
+ return retrieve(type, myRemoved);
+ }
+
+ public List retrieveChanged(Class type) {
+ return retrieve(type, myChanged);
+ }
+
+ public void clear() {
+ myAdded.clear();
+ myRemoved.clear();
+ myChanged.clear();
+ }
+
+
+ private static List retrieve(Class type, List list) {
+ final List result = new ArrayList();
+ final Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ JpsElement element = iterator.next();
+ if (type.isInstance(element)) {
+ result.add(type.cast(element));
+ iterator.remove();
+ }
+ }
+ return result;
+ }
+}