diff --git a/scm-plugin-backend/pom.xml b/scm-plugin-backend/pom.xml
index a07f09751d..236ea1e6e1 100644
--- a/scm-plugin-backend/pom.xml
+++ b/scm-plugin-backend/pom.xml
@@ -29,6 +29,12 @@
scm-core1.1-SNAPSHOT
+
+
+ com.sun.jersey.contribs
+ jersey-guice
+ ${jersey.version}
+ ch.qos.logback
@@ -39,6 +45,25 @@
+
+
+
+
+ org.mortbay.jetty
+ maven-jetty-plugin
+ 6.1.26
+
+ 8005
+ STOP
+ ${project.build.javaLevel}
+ ${project.build.javaLevel}
+ ${project.build.sourceEncoding}
+ 0
+
+
+
+
+
scm-plugin-backend
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendConfiguration.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendConfiguration.java
index b7da5ae808..c8bbc32cb5 100644
--- a/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendConfiguration.java
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/BackendConfiguration.java
@@ -41,7 +41,7 @@ import sonia.scm.xml.XmlIntervalAdapter;
import java.io.File;
-import java.util.List;
+import java.util.Set;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@@ -65,7 +65,7 @@ public class BackendConfiguration
*
* @return
*/
- public List getDirectories()
+ public Set getDirectories()
{
return directories;
}
@@ -76,7 +76,7 @@ public class BackendConfiguration
*
* @return
*/
- public List getRepositories()
+ public Set getRepositories()
{
return repositories;
}
@@ -111,7 +111,7 @@ public class BackendConfiguration
*
* @param directories
*/
- public void setDirectories(List directories)
+ public void setDirectories(Set directories)
{
this.directories = directories;
}
@@ -133,7 +133,7 @@ public class BackendConfiguration
*
* @param repositories
*/
- public void setRepositories(List repositories)
+ public void setRepositories(Set repositories)
{
this.repositories = repositories;
}
@@ -154,7 +154,7 @@ public class BackendConfiguration
/** Field description */
@XmlElement(name = "directory")
@XmlElementWrapper(name = "directories")
- private List directories;
+ private Set directories;
/** Field description */
private boolean multithreaded = true;
@@ -162,7 +162,7 @@ public class BackendConfiguration
/** Field description */
@XmlElement(name = "repository")
@XmlElementWrapper(name = "repositories")
- private List repositories;
+ private Set repositories;
/** Field description */
@XmlElement(name = "scann-interval")
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/ScmBackendModule.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/ScmBackendModule.java
index 772387e4e0..f5fc300338 100644
--- a/scm-plugin-backend/src/main/java/sonia/scm/plugin/ScmBackendModule.java
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/ScmBackendModule.java
@@ -47,8 +47,14 @@ import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
+import com.sun.jersey.api.core.PackagesResourceConfig;
+import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
+
import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
import javax.xml.bind.JAXB;
/**
@@ -70,6 +76,9 @@ public class ScmBackendModule extends ServletModule
/** Field description */
public static final String FILE_CONFIG = "config.xml";
+ /** Field description */
+ public static final String PATTERN_API = "/api/*";
+
//~--- methods --------------------------------------------------------------
/**
@@ -104,6 +113,12 @@ public class ScmBackendModule extends ServletModule
bind(PluginBackend.class).to(DefaultPluginBackend.class);
bind(PluginScannerFactory.class).to(DefaultPluginScannerFactory.class);
bind(PluginScannerScheduler.class).to(TimerPluginScannerScheduler.class);
+
+ Map params = new HashMap();
+
+ params.put(PackagesResourceConfig.PROPERTY_PACKAGES,
+ "sonia.scm.plugin.rest");
+ serve(PATTERN_API).with(GuiceContainer.class, params);
}
/**
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/DefaultPluginFilter.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/DefaultPluginFilter.java
new file mode 100644
index 0000000000..0b74a605f9
--- /dev/null
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/DefaultPluginFilter.java
@@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2010, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+
+
+
+package sonia.scm.plugin.rest;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import sonia.scm.plugin.PluginFilter;
+import sonia.scm.plugin.PluginInformation;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class DefaultPluginFilter implements PluginFilter
+{
+
+ /** Field description */
+ public static final String VERSION_SNAPSHOT = "SNAPSHOT";
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param version
+ * @param os
+ * @param arch
+ * @param snapshot
+ */
+ public DefaultPluginFilter(String version, String os, String arch,
+ boolean snapshot)
+ {
+ this.version = version;
+ this.os = os;
+ this.arch = arch;
+ this.snapshot = snapshot;
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param plugin
+ *
+ * @return
+ */
+ @Override
+ public boolean accept(PluginInformation plugin)
+ {
+ return snapshot
+ ||!plugin.getVersion().toUpperCase().contains(VERSION_SNAPSHOT);
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private String arch;
+
+ /** Field description */
+ private String os;
+
+ /** Field description */
+ private boolean snapshot;
+
+ /** Field description */
+ private String version;
+}
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/PluginInformationComparator.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/PluginInformationComparator.java
new file mode 100644
index 0000000000..110c8f2252
--- /dev/null
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/PluginInformationComparator.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) 2010, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+
+
+
+package sonia.scm.plugin.rest;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import sonia.scm.plugin.PluginInformation;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.util.Comparator;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class PluginInformationComparator
+ implements Comparator
+{
+
+ /** Field description */
+ public static final PluginInformationComparator INSTANCE =
+ new PluginInformationComparator();
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param plugin
+ * @param otherPlugin
+ *
+ * @return
+ */
+ @Override
+ public int compare(PluginInformation plugin, PluginInformation otherPlugin)
+ {
+ int c = plugin.getGroupId().compareTo(otherPlugin.getGroupId());
+
+ if (c == 0)
+ {
+ c = plugin.getArtifactId().compareTo(otherPlugin.getArtifactId());
+
+ if (c == 0)
+ {
+ c = plugin.getVersion().compareTo(otherPlugin.getVersion());
+ }
+ }
+
+ return c;
+ }
+}
diff --git a/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/PluginResource.java b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/PluginResource.java
new file mode 100644
index 0000000000..6be9006f7e
--- /dev/null
+++ b/scm-plugin-backend/src/main/java/sonia/scm/plugin/rest/PluginResource.java
@@ -0,0 +1,204 @@
+/**
+ * Copyright (c) 2010, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+
+
+
+package sonia.scm.plugin.rest;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.inject.Inject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import sonia.scm.plugin.BackendConfiguration;
+import sonia.scm.plugin.PluginBackend;
+import sonia.scm.plugin.PluginCenter;
+import sonia.scm.plugin.PluginInformation;
+import sonia.scm.plugin.PluginVersion;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Path("{version}/plugins")
+public class PluginResource
+{
+
+ /** the logger for PluginResource */
+ private static final Logger logger =
+ LoggerFactory.getLogger(PluginResource.class);
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param backend
+ * @param configuration
+ */
+ @Inject
+ public PluginResource(PluginBackend backend,
+ BackendConfiguration configuration)
+ {
+ this.backend = backend;
+ this.configuration = configuration;
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param version
+ * @param snapshot
+ *
+ * @return
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ public Response getPlugins(
+ @PathParam("version") String version,
+ @DefaultValue("false") @QueryParam("snapshot") boolean snapshot)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("load plugins for version {}, include snapshots: {}",
+ version, Boolean.toString(snapshot));
+ }
+
+ List plugins =
+ backend.getPlugins(new DefaultPluginFilter(version, null, null,
+ snapshot));
+ PluginCenter pc = new PluginCenter();
+
+ pc.setPlugins(getNewestPlugins(plugins));
+ pc.setRepositories(configuration.getRepositories());
+
+ return Response.ok(pc).build();
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param plugins
+ *
+ * @return
+ */
+ private Set getNewestPlugins(
+ List plugins)
+ {
+ Collections.sort(plugins, PluginInformationComparator.INSTANCE);
+
+ Set pluginSet = new HashSet();
+ PluginInformation newest = null;
+
+ for (PluginInformation plugin : plugins)
+ {
+ if (newest == null)
+ {
+ newest = plugin;
+ }
+ else if (isSamePlugin(plugin, newest))
+ {
+ if (isNewer(plugin, newest))
+ {
+ newest = plugin;
+ }
+ }
+ else
+ {
+ pluginSet.add(newest);
+ newest = plugin;
+ }
+ }
+
+ return pluginSet;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param plugin
+ * @param newest
+ *
+ * @return
+ */
+ private boolean isNewer(PluginInformation plugin, PluginInformation newest)
+ {
+ return new PluginVersion(plugin.getVersion()).isNewer(newest.getVersion());
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param plugin
+ * @param otherPlugin
+ *
+ * @return
+ */
+ private boolean isSamePlugin(PluginInformation plugin,
+ PluginInformation otherPlugin)
+ {
+ return plugin.getGroupId().equals(otherPlugin.getGroupId())
+ && plugin.getArtifactId().equals(otherPlugin.getArtifactId());
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private PluginBackend backend;
+
+ /** Field description */
+ private BackendConfiguration configuration;
+}
diff --git a/scm-plugin-backend/src/main/resources/logback.xml b/scm-plugin-backend/src/main/resources/logback.xml
index d0ce050084..6eac1b2ed1 100644
--- a/scm-plugin-backend/src/main/resources/logback.xml
+++ b/scm-plugin-backend/src/main/resources/logback.xml
@@ -19,6 +19,7 @@
+