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-core 1.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 @@ +