diff --git a/idea/src/META-INF/maven.xml b/idea/src/META-INF/maven.xml
index c43b790fb22..a3da2212a9c 100644
--- a/idea/src/META-INF/maven.xml
+++ b/idea/src/META-INF/maven.xml
@@ -5,6 +5,7 @@
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMavenArchetypesProvider.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMavenArchetypesProvider.kt
new file mode 100644
index 00000000000..97c4eb7709e
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMavenArchetypesProvider.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.configuration
+
+import com.google.gson.JsonElement
+import com.google.gson.JsonParser
+import com.intellij.util.net.HttpConfigurable
+import org.jetbrains.idea.maven.dom.MavenVersionComparable
+import org.jetbrains.idea.maven.indices.MavenArchetypesProvider
+import org.jetbrains.idea.maven.model.MavenArchetype
+import org.jetbrains.kotlin.idea.KotlinPluginUtil
+import org.jetbrains.kotlin.utils.ifEmpty
+import java.net.HttpURLConnection
+import java.net.URLEncoder
+import java.util.concurrent.TimeUnit
+
+class KotlinMavenArchetypesProvider(val kotlinPluginVersion: String) : MavenArchetypesProvider {
+ constructor() : this(KotlinPluginUtil.getPluginVersion())
+
+ val VERSIONS_LIST_URL = mavenSearchUrl("org.jetbrains.kotlin", packaging = "maven-archetype", rowsLimit = 1000)
+ private val versionPrefix by lazy { """^\d+\.\d+\.""".toRegex().find(kotlinPluginVersion)?.value ?: "1.0." }
+
+ private val archetypesBlocking by lazy {
+ try {
+ loadVersions().ifEmpty { defaultArchetypes() }
+ } catch (t: Throwable) {
+ defaultArchetypes()
+ }
+ }
+
+ override fun getArchetypes() = archetypesBlocking.toMutableList()
+
+ private fun defaultArchetypes() = listOf(MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.0", null, null))
+
+ private fun loadVersions(): List {
+ return connectAndApply(VERSIONS_LIST_URL) { urlConnection ->
+ urlConnection.inputStream.bufferedReader().use { reader ->
+ extractVersions(JsonParser().parse(reader))
+ }
+ }
+ }
+
+ internal fun extractVersions(root: JsonElement) =
+ root.asJsonObject.get("response")
+ .asJsonObject.get("docs")
+ .asJsonArray
+ .map { it.asJsonObject }
+ .map { MavenArchetype(it.get("g").asString, it.get("a").asString, it.get("v").asString, null, null) }
+ .filter { it.version?.startsWith(versionPrefix) ?: false }
+ .maxBy { MavenVersionComparable(it.version) }
+ .let { listOfNotNull(it) }
+
+ private fun mavenSearchUrl(group: String, artifactId: String? = null, version: String? = null, packaging: String? = null, rowsLimit: Int = 20): String {
+ val q = listOf(
+ "g" to group,
+ "a" to artifactId,
+ "v" to version,
+ "p" to packaging
+ )
+ .filter { it.second != null }
+ .map { "${it.first}:\"${it.second}\"" }
+ .joinToString(separator = " AND ")
+
+ return "http://search.maven.org/solrsearch/select?q=${q.encodeURL()}&core=gav&rows=$rowsLimit&wt=json"
+ }
+
+ private fun connectAndApply(url: String, timeoutSeconds: Int = 15, block: (HttpURLConnection) -> R): R {
+ return HttpConfigurable.getInstance().openHttpConnection(url).use { urlConnection ->
+ val timeout = TimeUnit.SECONDS.toMillis(timeoutSeconds.toLong()).toInt()
+ urlConnection.connectTimeout = timeout
+ urlConnection.readTimeout = timeout
+
+ urlConnection.connect()
+ block(urlConnection)
+ }
+ }
+
+ private fun HttpURLConnection.use(block: (HttpURLConnection) -> R): R =
+ try {
+ block(this)
+ }
+ finally {
+ disconnect()
+ }
+
+ private fun String.encodeURL() = URLEncoder.encode(this, "UTF-8")
+}
diff --git a/idea/testData/configuration/extractVersions/maven-central-response.json b/idea/testData/configuration/extractVersions/maven-central-response.json
new file mode 100644
index 00000000000..ba555720a93
--- /dev/null
+++ b/idea/testData/configuration/extractVersions/maven-central-response.json
@@ -0,0 +1,122 @@
+{
+ "responseHeader": {
+ "status": 0,
+ "QTime": 2,
+ "params": {
+ "fl": "id,g,a,v,p,ec,timestamp,tags",
+ "sort": "score desc,timestamp desc,g asc,a asc,v desc",
+ "indent": "off",
+ "q": "g:\"org.jetbrains.kotlin\" AND p:\"maven-archetype\"",
+ "core": "gav",
+ "wt": "json",
+ "rows": "200",
+ "version": "2.2"
+ }
+ },
+ "response": {
+ "numFound": 3,
+ "start": 0,
+ "docs": [
+ {
+ "id": "org.jetbrains.kotlin:kotlin-archetype-jvm:1.0.0",
+ "g": "org.jetbrains.kotlin",
+ "a": "kotlin-archetype-jvm",
+ "v": "1.0.0",
+ "p": "maven-archetype",
+ "timestamp": 1458127798000,
+ "tags": [
+ "using",
+ "restful",
+ "creates",
+ "example",
+ "webservice"
+ ],
+ "ec": [
+ "-sources.jar",
+ ".jar",
+ ".pom"
+ ]
+ },
+ {
+ "id": "org.jetbrains.kotlin:kotlin-archetype-js:1.0.0",
+ "g": "org.jetbrains.kotlin",
+ "a": "kotlin-archetype-js",
+ "v": "1.0.0",
+ "p": "maven-archetype",
+ "timestamp": 1458127798000,
+ "tags": [
+ "using",
+ "restful",
+ "creates",
+ "example",
+ "webservice"
+ ],
+ "ec": [
+ "-sources.jar",
+ ".jar",
+ ".pom"
+ ]
+ },
+ {
+ "id": "org.jetbrains.kotlin:kotlin-archetype-jvm:1.0.1",
+ "g": "org.jetbrains.kotlin",
+ "a": "kotlin-archetype-jvm",
+ "v": "1.0.1",
+ "p": "maven-archetype",
+ "timestamp": 1458127798000,
+ "tags": [
+ "using",
+ "restful",
+ "creates",
+ "example",
+ "webservice"
+ ],
+ "ec": [
+ "-sources.jar",
+ ".jar",
+ ".pom"
+ ]
+ },
+ {
+ "id": "org.jetbrains.kotlin:kotlin-archetype-jvm:1.0.1",
+ "g": "org.jetbrains.kotlin",
+ "a": "kotlin-archetype-jvm",
+ "v": "1.0.1-2",
+ "p": "maven-archetype",
+ "timestamp": 1458127798000,
+ "tags": [
+ "using",
+ "restful",
+ "creates",
+ "example",
+ "webservice"
+ ],
+ "ec": [
+ "-sources.jar",
+ ".jar",
+ ".pom"
+ ]
+ },
+ {
+ "id": "org.jetbrains.kotlin:kotlin-archetype-jvm:1.1.2",
+ "g": "org.jetbrains.kotlin",
+ "a": "kotlin-archetype-jvm",
+ "v": "1.1.2",
+ "p": "maven-archetype",
+ "timestamp": 1458127798000,
+ "tags": [
+ "using",
+ "restful",
+ "creates",
+ "example",
+ "webservice"
+ ],
+ "ec": [
+ "-sources.jar",
+ ".jar",
+ ".pom"
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/configuration/KotlinMavenArchetypesProviderTest.kt b/idea/tests/org/jetbrains/kotlin/idea/configuration/KotlinMavenArchetypesProviderTest.kt
new file mode 100644
index 00000000000..48af5af2e77
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/configuration/KotlinMavenArchetypesProviderTest.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.configuration
+
+import com.google.gson.JsonParser
+import org.jetbrains.idea.maven.model.MavenArchetype
+import org.junit.Test
+
+import org.junit.Assert.*
+import java.io.File
+
+class KotlinMavenArchetypesProviderTest {
+ private val BASE_PATH = "idea/testData/configuration/"
+
+ @Test
+ fun extractVersions() {
+ val file = File(BASE_PATH, "extractVersions/maven-central-response.json")
+ assertTrue("Test data is missing", file.exists())
+
+ val json = file.bufferedReader().use {
+ JsonParser().parse(it)
+ }
+
+ val versions = KotlinMavenArchetypesProvider("1.0.0-Release-Something-1886").extractVersions(json)
+
+ assertEquals(
+ listOf(
+ MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.1-2", null, null)
+ ).sortedBy { it.artifactId + "." + it.version },
+ versions.sortedBy { it.artifactId + "." + it.version }
+ )
+ }
+
+ @Test
+ fun extractVersionsNewPlugin() {
+ val file = File(BASE_PATH, "extractVersions/maven-central-response.json")
+ assertTrue("Test data is missing", file.exists())
+
+ val json = file.bufferedReader().use {
+ JsonParser().parse(it)
+ }
+
+ val versions = KotlinMavenArchetypesProvider("1.1.0-Next-Release-Something-9999").extractVersions(json)
+
+ assertEquals(
+ listOf(
+ MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.1.2", null, null)
+ ).sortedBy { it.artifactId + "." + it.version },
+ versions.sortedBy { it.artifactId + "." + it.version }
+ )
+ }
+}
\ No newline at end of file