mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-18 03:01:05 +01:00
create new simplified PluginManager API
This commit is contained in:
20
scm-core/src/main/java/sonia/scm/plugin/AvailablePlugin.java
Normal file
20
scm-core/src/main/java/sonia/scm/plugin/AvailablePlugin.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package sonia.scm.plugin;
|
||||
|
||||
public class AvailablePlugin implements Plugin {
|
||||
|
||||
private final AvailablePluginDescriptor pluginDescriptor;
|
||||
|
||||
public AvailablePlugin(AvailablePluginDescriptor pluginDescriptor) {
|
||||
this.pluginDescriptor = pluginDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AvailablePluginDescriptor getDescriptor() {
|
||||
return pluginDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginState getState() {
|
||||
return PluginState.AVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package sonia.scm.plugin;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class AvailablePluginDescriptor implements PluginDescriptor {
|
||||
|
||||
private final PluginInformation information;
|
||||
private final PluginCondition condition;
|
||||
private final Set<String> dependencies;
|
||||
|
||||
public AvailablePluginDescriptor(PluginInformation information, PluginCondition condition, Set<String> dependencies) {
|
||||
this.information = information;
|
||||
this.condition = condition;
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginInformation getInformation() {
|
||||
return information;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginCondition getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ import java.util.Set;
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@XmlRootElement
|
||||
@XmlRootElement(name = "plugin")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public final class InstalledPluginDescriptor extends ScmModule implements PluginDescriptor
|
||||
{
|
||||
@@ -247,6 +247,7 @@ public final class InstalledPluginDescriptor extends ScmModule implements Plugin
|
||||
private Set<String> dependencies;
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "information")
|
||||
private PluginInformation information;
|
||||
|
||||
/** Field description */
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@XmlRootElement(name = "plugin-center")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class PluginCenter implements Serializable
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
private static final long serialVersionUID = -6414175308610267397L;
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<PluginInformation> getPlugins()
|
||||
{
|
||||
return plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<PluginRepository> getRepositories()
|
||||
{
|
||||
return repositories;
|
||||
}
|
||||
|
||||
//~--- set methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param plugins
|
||||
*/
|
||||
public void setPlugins(Set<PluginInformation> plugins)
|
||||
{
|
||||
this.plugins = plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repositories
|
||||
*/
|
||||
public void setRepositories(Set<PluginRepository> repositories)
|
||||
{
|
||||
this.repositories = repositories;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "plugin")
|
||||
@XmlElementWrapper(name = "plugins")
|
||||
private Set<PluginInformation> plugins = new HashSet<PluginInformation>();
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "repository")
|
||||
@XmlElementWrapper(name = "repositories")
|
||||
private Set<PluginRepository> repositories = new HashSet<PluginRepository>();
|
||||
}
|
||||
@@ -71,7 +71,6 @@ public class PluginInformation implements PermissionObject, Validateable, Clonea
|
||||
private String category;
|
||||
private String avatarUrl;
|
||||
private PluginCondition condition;
|
||||
private PluginState state;
|
||||
|
||||
@Override
|
||||
public PluginInformation clone() {
|
||||
@@ -83,7 +82,6 @@ public class PluginInformation implements PermissionObject, Validateable, Clonea
|
||||
clone.setAuthor(author);
|
||||
clone.setCategory(category);
|
||||
clone.setAvatarUrl(avatarUrl);
|
||||
clone.setState(state);
|
||||
if (condition != null) {
|
||||
clone.setCondition(condition.clone());
|
||||
}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.6
|
||||
*/
|
||||
public class PluginInformationComparator
|
||||
implements Comparator<PluginInformation>, Serializable
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final PluginInformationComparator INSTANCE =
|
||||
new PluginInformationComparator();
|
||||
|
||||
/** Field description */
|
||||
private static final long serialVersionUID = -8339752498853225668L;
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param plugin
|
||||
* @param other
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int compare(PluginInformation plugin, PluginInformation other)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
result = Util.compare(plugin.getName(), other.getName());
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
PluginState state = plugin.getState();
|
||||
PluginState otherState = other.getState();
|
||||
|
||||
if ((state != null) && (otherState != null))
|
||||
{
|
||||
result = state.getCompareValue() - otherState.getCompareValue();
|
||||
}
|
||||
else if ((state == null) && (otherState != null))
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
else if ((state != null) && (otherState == null))
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -33,113 +33,50 @@
|
||||
|
||||
package sonia.scm.plugin;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* The plugin manager is responsible for plugin related tasks, such as install, uninstall or updating.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public interface PluginManager
|
||||
{
|
||||
public interface PluginManager {
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
* Returns the available plugin with the given name.
|
||||
* @param name of plugin
|
||||
* @return optional available plugin.
|
||||
*/
|
||||
public void clearCache();
|
||||
Optional<AvailablePlugin> getAvailable(String name);
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
* Returns the installed plugin with the given name.
|
||||
* @param name of plugin
|
||||
* @return optional installed plugin.
|
||||
*/
|
||||
public void install(String id);
|
||||
Optional<InstalledPlugin> getInstalled(String name);
|
||||
|
||||
|
||||
/**
|
||||
* Installs a plugin package from a inputstream.
|
||||
* Returns all installed plugins.
|
||||
*
|
||||
*
|
||||
* @param packageStream package input stream
|
||||
*
|
||||
* @throws IOException
|
||||
* @since 1.21
|
||||
* @return a list of installed plugins.
|
||||
*/
|
||||
public void installPackage(InputStream packageStream) throws IOException;
|
||||
List<InstalledPlugin> getInstalled();
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns all available plugins. The list contains the plugins which are loaded from the plugin center, but without
|
||||
* the installed plugins.
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
* @return a list of available plugins.
|
||||
*/
|
||||
public void uninstall(String id);
|
||||
List<AvailablePlugin> getAvailable();
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Installs the plugin with the given name from the list of available plugins.
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
* @param name plugin name
|
||||
*/
|
||||
public void update(String id);
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public PluginInformation get(String id);
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param filter
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<PluginInformation> get(Predicate<PluginInformation> filter);
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<PluginInformation> getAll();
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<PluginInformation> getAvailable();
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<PluginInformation> getAvailableUpdates();
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<PluginInformation> getInstalled();
|
||||
void install(String name);
|
||||
}
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class PluginRepository implements Serializable
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
private static final long serialVersionUID = -9504354306304731L;
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*/
|
||||
PluginRepository() {}
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
* @param url
|
||||
*/
|
||||
public PluginRepository(String id, String url)
|
||||
{
|
||||
this.id = id;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param obj
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getClass() != obj.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final PluginRepository other = (PluginRepository) obj;
|
||||
|
||||
return Objects.equal(id, other.id) && Objects.equal(url, other.url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hashCode(id, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return MoreObjects.toStringHelper(this).add("id", id).add("url",
|
||||
url).toString();
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getUrl()
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private String id;
|
||||
|
||||
/** Field description */
|
||||
private String url;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class StatePluginPredicate implements Predicate<PluginInformation>
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param state
|
||||
*/
|
||||
public StatePluginPredicate(PluginState state)
|
||||
{
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param plugin
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean apply(PluginInformation plugin)
|
||||
{
|
||||
return state == plugin.getState();
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private final PluginState state;
|
||||
}
|
||||
@@ -3,11 +3,10 @@ package sonia.scm.api.v2.resources;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import sonia.scm.plugin.AvailablePlugin;
|
||||
import sonia.scm.plugin.InstalledPluginDescriptor;
|
||||
import sonia.scm.plugin.PluginInformation;
|
||||
import sonia.scm.plugin.PluginManager;
|
||||
import sonia.scm.plugin.PluginPermissions;
|
||||
import sonia.scm.plugin.PluginState;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -18,9 +17,8 @@ import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
import static sonia.scm.NotFoundException.notFound;
|
||||
@@ -53,11 +51,8 @@ public class AvailablePluginResource {
|
||||
@Produces(VndMediaType.PLUGIN_COLLECTION)
|
||||
public Response getAvailablePlugins() {
|
||||
PluginPermissions.read().check();
|
||||
Collection<PluginInformation> plugins = pluginManager.getAvailable()
|
||||
.stream()
|
||||
.filter(plugin -> plugin.getState().equals(PluginState.AVAILABLE))
|
||||
.collect(Collectors.toList());
|
||||
return Response.ok(collectionMapper.map(plugins)).build();
|
||||
List<AvailablePlugin> available = pluginManager.getAvailable();
|
||||
return Response.ok(collectionMapper.mapAvailable(available)).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +61,7 @@ public class AvailablePluginResource {
|
||||
* @return available plugin.
|
||||
*/
|
||||
@GET
|
||||
@Path("/{name}/{version}")
|
||||
@Path("/{name}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 404, condition = "not found"),
|
||||
@@ -74,12 +69,9 @@ public class AvailablePluginResource {
|
||||
})
|
||||
@TypeHint(PluginDto.class)
|
||||
@Produces(VndMediaType.PLUGIN)
|
||||
public Response getAvailablePlugin(@PathParam("name") String name, @PathParam("version") String version) {
|
||||
public Response getAvailablePlugin(@PathParam("name") String name) {
|
||||
PluginPermissions.read().check();
|
||||
Optional<PluginInformation> plugin = pluginManager.getAvailable()
|
||||
.stream()
|
||||
.filter(p -> p.getId().equals(name + ":" + version))
|
||||
.findFirst();
|
||||
Optional<AvailablePlugin> plugin = pluginManager.getAvailable(name);
|
||||
if (plugin.isPresent()) {
|
||||
return Response.ok(mapper.map(plugin.get())).build();
|
||||
} else {
|
||||
@@ -90,19 +82,18 @@ public class AvailablePluginResource {
|
||||
/**
|
||||
* Triggers plugin installation.
|
||||
* @param name plugin artefact name
|
||||
* @param version plugin version
|
||||
* @return HTTP Status.
|
||||
*/
|
||||
@POST
|
||||
@Path("/{name}/{version}/install")
|
||||
@Path("/{name}/install")
|
||||
@Consumes(VndMediaType.PLUGIN)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response installPlugin(@PathParam("name") String name, @PathParam("version") String version) {
|
||||
public Response installPlugin(@PathParam("name") String name) {
|
||||
PluginPermissions.manage().check();
|
||||
pluginManager.install(name + ":" + version);
|
||||
pluginManager.install(name);
|
||||
return Response.ok().build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,10 @@ package sonia.scm.api.v2.resources;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import sonia.scm.plugin.InstalledPlugin;
|
||||
import sonia.scm.plugin.InstalledPluginDescriptor;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
import sonia.scm.plugin.PluginManager;
|
||||
import sonia.scm.plugin.PluginPermissions;
|
||||
import sonia.scm.plugin.InstalledPlugin;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -16,7 +15,6 @@ import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -25,17 +23,15 @@ import static sonia.scm.NotFoundException.notFound;
|
||||
|
||||
public class InstalledPluginResource {
|
||||
|
||||
private final PluginLoader pluginLoader;
|
||||
private final PluginDtoCollectionMapper collectionMapper;
|
||||
private final PluginDtoMapper mapper;
|
||||
private final PluginManager pluginManager;
|
||||
|
||||
@Inject
|
||||
public InstalledPluginResource(PluginLoader pluginLoader, PluginDtoCollectionMapper collectionMapper, PluginDtoMapper mapper, PluginManager pluginManager) {
|
||||
this.pluginLoader = pluginLoader;
|
||||
public InstalledPluginResource(PluginManager pluginManager, PluginDtoCollectionMapper collectionMapper, PluginDtoMapper mapper) {
|
||||
this.pluginManager = pluginManager;
|
||||
this.collectionMapper = collectionMapper;
|
||||
this.mapper = mapper;
|
||||
this.pluginManager = pluginManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,8 +49,8 @@ public class InstalledPluginResource {
|
||||
@Produces(VndMediaType.PLUGIN_COLLECTION)
|
||||
public Response getInstalledPlugins() {
|
||||
PluginPermissions.read().check();
|
||||
List<InstalledPlugin> plugins = new ArrayList<>(pluginLoader.getInstalledPlugins());
|
||||
return Response.ok(collectionMapper.map(plugins)).build();
|
||||
List<InstalledPlugin> plugins = pluginManager.getInstalled();
|
||||
return Response.ok(collectionMapper.mapInstalled(plugins)).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,13 +71,9 @@ public class InstalledPluginResource {
|
||||
@Produces(VndMediaType.PLUGIN)
|
||||
public Response getInstalledPlugin(@PathParam("name") String name) {
|
||||
PluginPermissions.read().check();
|
||||
Optional<PluginDto> pluginDto = pluginLoader.getInstalledPlugins()
|
||||
.stream()
|
||||
.filter(plugin -> name.equals(plugin.getDescriptor().getInformation().getName()))
|
||||
.map(mapper::map)
|
||||
.findFirst();
|
||||
Optional<InstalledPlugin> pluginDto = pluginManager.getInstalled(name);
|
||||
if (pluginDto.isPresent()) {
|
||||
return Response.ok(pluginDto.get()).build();
|
||||
return Response.ok(mapper.map(pluginDto.get())).build();
|
||||
} else {
|
||||
throw notFound(entity(InstalledPluginDescriptor.class, name));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.inject.Inject;
|
||||
import de.otto.edison.hal.Embedded;
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
import de.otto.edison.hal.Links;
|
||||
import sonia.scm.plugin.AvailablePlugin;
|
||||
import sonia.scm.plugin.PluginInformation;
|
||||
import sonia.scm.plugin.InstalledPlugin;
|
||||
|
||||
@@ -25,12 +26,12 @@ public class PluginDtoCollectionMapper {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public HalRepresentation map(List<InstalledPlugin> plugins) {
|
||||
public HalRepresentation mapInstalled(List<InstalledPlugin> plugins) {
|
||||
List<PluginDto> dtos = plugins.stream().map(mapper::map).collect(toList());
|
||||
return new HalRepresentation(createInstalledPluginsLinks(), embedDtos(dtos));
|
||||
}
|
||||
|
||||
public HalRepresentation map(Collection<PluginInformation> plugins) {
|
||||
public HalRepresentation mapAvailable(List<AvailablePlugin> plugins) {
|
||||
List<PluginDto> dtos = plugins.stream().map(mapper::map).collect(toList());
|
||||
return new HalRepresentation(createAvailablePluginsLinks(), embedDtos(dtos));
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.Links;
|
||||
import org.mapstruct.AfterMapping;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.MappingTarget;
|
||||
import org.mapstruct.ObjectFactory;
|
||||
import sonia.scm.plugin.Plugin;
|
||||
import sonia.scm.plugin.PluginInformation;
|
||||
import sonia.scm.plugin.PluginState;
|
||||
import sonia.scm.plugin.InstalledPlugin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -20,23 +18,23 @@ public abstract class PluginDtoMapper {
|
||||
@Inject
|
||||
private ResourceLinks resourceLinks;
|
||||
|
||||
public PluginDto map(InstalledPlugin plugin) {
|
||||
return map(plugin.getDescriptor().getInformation());
|
||||
}
|
||||
public abstract void map(PluginInformation plugin, @MappingTarget PluginDto dto);
|
||||
|
||||
public abstract PluginDto map(PluginInformation plugin);
|
||||
|
||||
@AfterMapping
|
||||
protected void appendCategory(@MappingTarget PluginDto dto) {
|
||||
public PluginDto map(Plugin plugin) {
|
||||
PluginDto dto = createDto(plugin);
|
||||
map(plugin.getDescriptor().getInformation(), dto);
|
||||
if (dto.getCategory() == null) {
|
||||
dto.setCategory("Miscellaneous");
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
|
||||
@ObjectFactory
|
||||
public PluginDto createDto(PluginInformation pluginInformation) {
|
||||
private PluginDto createDto(Plugin plugin) {
|
||||
Links.Builder linksBuilder;
|
||||
if (pluginInformation.getState() != null && pluginInformation.getState().equals(PluginState.AVAILABLE)) {
|
||||
|
||||
PluginInformation pluginInformation = plugin.getDescriptor().getInformation();
|
||||
|
||||
if (plugin.getState() != null && plugin.getState().equals(PluginState.AVAILABLE)) {
|
||||
linksBuilder = linkingTo()
|
||||
.self(resourceLinks.availablePlugin()
|
||||
.self(pluginInformation.getName(), pluginInformation.getVersion()));
|
||||
|
||||
@@ -35,685 +35,41 @@ package sonia.scm.plugin;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.github.legman.Subscribe;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.cache.Cache;
|
||||
import sonia.scm.cache.CacheManager;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.config.ScmConfigurationChangedEvent;
|
||||
import sonia.scm.io.ZipUnArchiver;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.util.IOUtil;
|
||||
import sonia.scm.util.SystemUtil;
|
||||
import sonia.scm.util.Util;
|
||||
import sonia.scm.version.Version;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.bind.JAXB;
|
||||
|
||||
import sonia.scm.net.ahc.AdvancedHttpClient;
|
||||
|
||||
import static sonia.scm.plugin.PluginCenterDtoMapper.*;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* TODO replace aether stuff.
|
||||
* TODO check AdvancedPluginConfiguration from 1.x
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
public class DefaultPluginManager implements PluginManager
|
||||
{
|
||||
public class DefaultPluginManager implements PluginManager {
|
||||
|
||||
/** Field description */
|
||||
public static final String CACHE_NAME = "sonia.cache.plugins";
|
||||
|
||||
/** Field description */
|
||||
public static final String ENCODING = "UTF-8";
|
||||
|
||||
/** the logger for DefaultPluginManager */
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(DefaultPluginManager.class);
|
||||
|
||||
/** enable or disable remote plugins */
|
||||
private static final boolean REMOTE_PLUGINS_ENABLED = true;
|
||||
|
||||
/** Field description */
|
||||
public static final Predicate<PluginInformation> FILTER_UPDATES =
|
||||
new StatePluginPredicate(PluginState.UPDATE_AVAILABLE);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
* @param context
|
||||
* @param configuration
|
||||
* @param pluginLoader
|
||||
* @param cacheManager
|
||||
* @param httpClient
|
||||
*/
|
||||
@Inject
|
||||
public DefaultPluginManager(SCMContextProvider context,
|
||||
ScmConfiguration configuration, PluginLoader pluginLoader,
|
||||
CacheManager cacheManager, AdvancedHttpClient httpClient)
|
||||
{
|
||||
this.context = context;
|
||||
this.configuration = configuration;
|
||||
this.cache = cacheManager.getCache(CACHE_NAME);
|
||||
this.httpClient = httpClient;
|
||||
installedPlugins = new HashMap<>();
|
||||
|
||||
for (InstalledPlugin wrapper : pluginLoader.getInstalledPlugins())
|
||||
{
|
||||
InstalledPluginDescriptor plugin = wrapper.getDescriptor();
|
||||
PluginInformation info = plugin.getInformation();
|
||||
|
||||
if ((info != null) && info.isValid())
|
||||
{
|
||||
installedPlugins.put(info.getId(), plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void clearCache()
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("clear plugin cache");
|
||||
public Optional<AvailablePlugin> getAvailable(String name) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
@Subscribe
|
||||
public void configChanged(ScmConfigurationChangedEvent config)
|
||||
{
|
||||
clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@Override
|
||||
public void install(String id)
|
||||
{
|
||||
PluginPermissions.manage().check();
|
||||
|
||||
PluginCenter center = getPluginCenter();
|
||||
|
||||
for (PluginInformation plugin : center.getPlugins())
|
||||
{
|
||||
String pluginId = plugin.getId();
|
||||
|
||||
if (Util.isNotEmpty(pluginId) && pluginId.equals(id))
|
||||
{
|
||||
plugin.setState(PluginState.INSTALLED);
|
||||
|
||||
// ugly workaround
|
||||
InstalledPluginDescriptor newPlugin = new InstalledPluginDescriptor();
|
||||
|
||||
// TODO check
|
||||
// newPlugin.setInformation(plugin);
|
||||
installedPlugins.put(id, newPlugin);
|
||||
}
|
||||
}
|
||||
public Optional<InstalledPlugin> getInstalled(String name) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param packageStream
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void installPackage(InputStream packageStream) throws IOException
|
||||
{
|
||||
PluginPermissions.manage().check();
|
||||
|
||||
File tempDirectory = Files.createTempDir();
|
||||
|
||||
try
|
||||
{
|
||||
new ZipUnArchiver().extractArchive(packageStream, tempDirectory);
|
||||
|
||||
InstalledPluginDescriptor plugin = JAXB.unmarshal(new File(tempDirectory, "plugin.xml"),
|
||||
InstalledPluginDescriptor.class);
|
||||
|
||||
PluginCondition condition = plugin.getCondition();
|
||||
|
||||
if ((condition != null) &&!condition.isSupported())
|
||||
{
|
||||
throw new PluginConditionFailedException(condition);
|
||||
public List<InstalledPlugin> getInstalled() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* AetherPluginHandler aph = new AetherPluginHandler(this, context,
|
||||
* configuration);
|
||||
* Collection<PluginRepository> repositories =
|
||||
* Sets.newHashSet(new PluginRepository("package-repository",
|
||||
* "file://".concat(tempDirectory.getAbsolutePath())));
|
||||
*
|
||||
* aph.setPluginRepositories(repositories);
|
||||
*
|
||||
* aph.install(plugin.getInformation().getId());
|
||||
*/
|
||||
plugin.getInformation().setState(PluginState.INSTALLED);
|
||||
installedPlugins.put(plugin.getInformation().getId(), plugin);
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.delete(tempDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@Override
|
||||
public void uninstall(String id)
|
||||
{
|
||||
PluginPermissions.manage().check();
|
||||
|
||||
InstalledPluginDescriptor plugin = installedPlugins.get(id);
|
||||
|
||||
if (plugin == null)
|
||||
{
|
||||
String pluginPrefix = getPluginIdPrefix(id);
|
||||
|
||||
for (String nid : installedPlugins.keySet())
|
||||
{
|
||||
if (nid.startsWith(pluginPrefix))
|
||||
{
|
||||
id = nid;
|
||||
plugin = installedPlugins.get(nid);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
public List<AvailablePlugin> getAvailable() {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (plugin == null)
|
||||
{
|
||||
throw new PluginNotInstalledException(id.concat(" is not install"));
|
||||
}
|
||||
|
||||
/*
|
||||
* if (pluginHandler == null)
|
||||
* {
|
||||
* getPluginCenter();
|
||||
* }
|
||||
*
|
||||
* pluginHandler.uninstall(id);
|
||||
*/
|
||||
installedPlugins.remove(id);
|
||||
preparePlugins(getPluginCenter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@Override
|
||||
public void update(String id)
|
||||
{
|
||||
PluginPermissions.manage().check();
|
||||
public void install(String name) {
|
||||
|
||||
String[] idParts = id.split(":");
|
||||
String name = idParts[0];
|
||||
PluginInformation installed = null;
|
||||
|
||||
for (PluginInformation info : getInstalled())
|
||||
{
|
||||
if (name.equals(info.getName()))
|
||||
{
|
||||
installed = info;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (installed == null)
|
||||
{
|
||||
StringBuilder msg = new StringBuilder(name);
|
||||
|
||||
msg.append(" is not install");
|
||||
|
||||
throw new PluginNotInstalledException(msg.toString());
|
||||
}
|
||||
|
||||
uninstall(installed.getId());
|
||||
install(id);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public PluginInformation get(String id)
|
||||
{
|
||||
PluginPermissions.read().check();
|
||||
|
||||
PluginInformation result = null;
|
||||
|
||||
for (PluginInformation info : getPluginCenter().getPlugins())
|
||||
{
|
||||
if (id.equals(info.getId()))
|
||||
{
|
||||
result = info;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param predicate
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Set<PluginInformation> get(Predicate<PluginInformation> predicate)
|
||||
{
|
||||
AssertUtil.assertIsNotNull(predicate);
|
||||
PluginPermissions.read().check();
|
||||
|
||||
Set<PluginInformation> infoSet = new HashSet<>();
|
||||
|
||||
filter(infoSet, getInstalled(), predicate);
|
||||
filter(infoSet, getPluginCenter().getPlugins(), predicate);
|
||||
|
||||
return infoSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Collection<PluginInformation> getAll()
|
||||
{
|
||||
PluginPermissions.read().check();
|
||||
|
||||
Set<PluginInformation> infoSet = getInstalled();
|
||||
|
||||
infoSet.addAll(getPluginCenter().getPlugins());
|
||||
|
||||
return infoSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Collection<PluginInformation> getAvailable()
|
||||
{
|
||||
PluginPermissions.read().check();
|
||||
|
||||
Set<PluginInformation> availablePlugins = new HashSet<>();
|
||||
Set<PluginInformation> centerPlugins = getPluginCenter().getPlugins();
|
||||
|
||||
for (PluginInformation info : centerPlugins)
|
||||
{
|
||||
if (!installedPlugins.containsKey(info.getName()))
|
||||
{
|
||||
availablePlugins.add(info);
|
||||
}
|
||||
}
|
||||
|
||||
return availablePlugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Set<PluginInformation> getAvailableUpdates()
|
||||
{
|
||||
PluginPermissions.read().check();
|
||||
|
||||
return get(FILTER_UPDATES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Set<PluginInformation> getInstalled()
|
||||
{
|
||||
PluginPermissions.read().check();
|
||||
|
||||
Set<PluginInformation> infoSet = new LinkedHashSet<>();
|
||||
|
||||
for (InstalledPluginDescriptor plugin : installedPlugins.values())
|
||||
{
|
||||
infoSet.add(plugin.getInformation());
|
||||
}
|
||||
|
||||
return infoSet;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
private String buildPluginUrl(String url)
|
||||
{
|
||||
String os = SystemUtil.getOS();
|
||||
String arch = SystemUtil.getArch();
|
||||
|
||||
try
|
||||
{
|
||||
os = URLEncoder.encode(os, ENCODING);
|
||||
}
|
||||
catch (UnsupportedEncodingException ex)
|
||||
{
|
||||
logger.error(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
return url.replace("{version}", context.getVersion()).replace("{os}",
|
||||
os).replace("{arch}", arch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param target
|
||||
* @param source
|
||||
* @param predicate
|
||||
*/
|
||||
private void filter(Set<PluginInformation> target,
|
||||
Collection<PluginInformation> source,
|
||||
Predicate<PluginInformation> predicate)
|
||||
{
|
||||
for (PluginInformation info : source)
|
||||
{
|
||||
if (predicate.apply(info))
|
||||
{
|
||||
target.add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param available
|
||||
*/
|
||||
private void preparePlugin(PluginInformation available)
|
||||
{
|
||||
PluginState state = PluginState.AVAILABLE;
|
||||
|
||||
for (PluginInformation installed : getInstalled())
|
||||
{
|
||||
if (isSamePlugin(available, installed))
|
||||
{
|
||||
if (installed.getVersion().equals(available.getVersion()))
|
||||
{
|
||||
state = PluginState.INSTALLED;
|
||||
}
|
||||
else if (isNewer(available, installed))
|
||||
{
|
||||
state = PluginState.UPDATE_AVAILABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = PluginState.NEWER_VERSION_INSTALLED;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
available.setState(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param pc
|
||||
*/
|
||||
private void preparePlugins(PluginCenter pc)
|
||||
{
|
||||
Set<PluginInformation> infoSet = pc.getPlugins();
|
||||
|
||||
if (infoSet != null)
|
||||
{
|
||||
Iterator<PluginInformation> pit = infoSet.iterator();
|
||||
|
||||
while (pit.hasNext())
|
||||
{
|
||||
PluginInformation available = pit.next();
|
||||
|
||||
if (isCorePluging(available))
|
||||
{
|
||||
pit.remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
preparePlugin(available);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private PluginCenter getPluginCenter()
|
||||
{
|
||||
PluginCenter center = cache.get(PluginCenter.class.getName());
|
||||
|
||||
if (center == null)
|
||||
{
|
||||
synchronized (DefaultPluginManager.class)
|
||||
{
|
||||
String pluginUrl = buildPluginUrl(configuration.getPluginUrl());
|
||||
logger.info("fetch plugin information from {}", pluginUrl);
|
||||
|
||||
if (REMOTE_PLUGINS_ENABLED && Util.isNotEmpty(pluginUrl))
|
||||
{
|
||||
try
|
||||
{
|
||||
center = new PluginCenter();
|
||||
PluginCenterDto pluginCenterDto = httpClient.get(pluginUrl).request().contentFromJson(PluginCenterDto.class);
|
||||
Set<PluginInformation> pluginInformationSet = map(pluginCenterDto.getEmbedded().getPlugins());
|
||||
center.setPlugins(pluginInformationSet);
|
||||
preparePlugins(center);
|
||||
cache.put(PluginCenter.class.getName(), center);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.error("could not load plugins from plugin center", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(center == null) {
|
||||
center = new PluginCenter();
|
||||
}
|
||||
}
|
||||
|
||||
return center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param pluginId
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getPluginIdPrefix(String pluginId)
|
||||
{
|
||||
return pluginId.substring(0, pluginId.lastIndexOf(':'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param available
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean isCorePluging(PluginInformation available)
|
||||
{
|
||||
boolean core = false;
|
||||
|
||||
for (InstalledPluginDescriptor installedPlugin : installedPlugins.values())
|
||||
{
|
||||
PluginInformation installed = installedPlugin.getInformation();
|
||||
|
||||
if (isSamePlugin(available, installed)
|
||||
&& (installed.getState() == PluginState.CORE))
|
||||
{
|
||||
core = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return core;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param available
|
||||
* @param installed
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean isNewer(PluginInformation available,
|
||||
PluginInformation installed)
|
||||
{
|
||||
boolean result = false;
|
||||
Version version = Version.parse(available.getVersion());
|
||||
|
||||
if (version != null)
|
||||
{
|
||||
result = version.isNewer(installed.getVersion());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param p1
|
||||
* @param p2
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean isSamePlugin(PluginInformation p1, PluginInformation p2)
|
||||
{
|
||||
return p1.getName().equals(p2.getName());
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private final Cache<String, PluginCenter> cache;
|
||||
|
||||
/** Field description */
|
||||
private final AdvancedHttpClient httpClient;
|
||||
|
||||
/** Field description */
|
||||
private final ScmConfiguration configuration;
|
||||
|
||||
/** Field description */
|
||||
private final SCMContextProvider context;
|
||||
|
||||
/** Field description */
|
||||
private final Map<String, InstalledPluginDescriptor> installedPlugins;
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class OverviewPluginPredicate implements Predicate<PluginInformation>
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final OverviewPluginPredicate INSTANCE =
|
||||
new OverviewPluginPredicate();
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param plugin
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean apply(PluginInformation plugin)
|
||||
{
|
||||
return plugin.getState() != PluginState.NEWER_VERSION_INSTALLED;
|
||||
}
|
||||
}
|
||||
@@ -237,7 +237,7 @@ public final class PluginProcessor
|
||||
}
|
||||
|
||||
InstalledPlugin plugin =
|
||||
createPluginWrapper(createParentPluginClassLoader(classLoader, parents),
|
||||
createPlugin(createParentPluginClassLoader(classLoader, parents),
|
||||
smp);
|
||||
|
||||
if (plugin != null)
|
||||
@@ -431,73 +431,36 @@ public final class PluginProcessor
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param classLoader
|
||||
* @param descriptor
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private InstalledPluginDescriptor createPlugin(ClassLoader classLoader, Path descriptor)
|
||||
{
|
||||
private InstalledPluginDescriptor createDescriptor(ClassLoader classLoader, Path descriptor) {
|
||||
ClassLoader ctxcl = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
|
||||
try
|
||||
{
|
||||
return (InstalledPluginDescriptor) context.createUnmarshaller().unmarshal(
|
||||
descriptor.toFile());
|
||||
}
|
||||
catch (JAXBException ex)
|
||||
{
|
||||
throw new PluginLoadException(
|
||||
"could not load plugin desriptor ".concat(descriptor.toString()), ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try {
|
||||
return (InstalledPluginDescriptor) context.createUnmarshaller().unmarshal(descriptor.toFile());
|
||||
} catch (JAXBException ex) {
|
||||
throw new PluginLoadException("could not load plugin desriptor ".concat(descriptor.toString()), ex);
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(ctxcl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param classLoader
|
||||
* @param smp
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private InstalledPlugin createPluginWrapper(ClassLoader classLoader,
|
||||
ExplodedSmp smp)
|
||||
throws IOException
|
||||
{
|
||||
InstalledPlugin wrapper = null;
|
||||
private InstalledPlugin createPlugin(ClassLoader classLoader, ExplodedSmp smp) throws IOException {
|
||||
InstalledPlugin plugin = null;
|
||||
Path directory = smp.getPath();
|
||||
Path descriptor = directory.resolve(PluginConstants.FILE_DESCRIPTOR);
|
||||
Path descriptorPath = directory.resolve(PluginConstants.FILE_DESCRIPTOR);
|
||||
|
||||
if (Files.exists(descriptor))
|
||||
{
|
||||
if (Files.exists(descriptorPath)) {
|
||||
ClassLoader cl = createClassLoader(classLoader, smp);
|
||||
|
||||
InstalledPluginDescriptor plugin = createPlugin(cl, descriptor);
|
||||
InstalledPluginDescriptor descriptor = createDescriptor(cl, descriptorPath);
|
||||
|
||||
WebResourceLoader resourceLoader = createWebResourceLoader(directory);
|
||||
|
||||
wrapper = new InstalledPlugin(plugin, cl, resourceLoader, directory);
|
||||
}
|
||||
else
|
||||
{
|
||||
plugin = new InstalledPlugin(descriptor, cl, resourceLoader, directory);
|
||||
} else {
|
||||
logger.warn("found plugin directory without plugin descriptor");
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,9 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.plugin.AvailablePlugin;
|
||||
import sonia.scm.plugin.AvailablePluginDescriptor;
|
||||
import sonia.scm.plugin.PluginCondition;
|
||||
import sonia.scm.plugin.PluginInformation;
|
||||
import sonia.scm.plugin.PluginManager;
|
||||
import sonia.scm.plugin.PluginState;
|
||||
@@ -27,6 +30,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@@ -87,10 +91,10 @@ class AvailablePluginResourceTest {
|
||||
|
||||
@Test
|
||||
void getAvailablePlugins() throws URISyntaxException, UnsupportedEncodingException {
|
||||
PluginInformation pluginInformation = new PluginInformation();
|
||||
pluginInformation.setState(PluginState.AVAILABLE);
|
||||
when(pluginManager.getAvailable()).thenReturn(Collections.singletonList(pluginInformation));
|
||||
when(collectionMapper.map(Collections.singletonList(pluginInformation))).thenReturn(new MockedResultDto());
|
||||
AvailablePlugin plugin = createPlugin();
|
||||
|
||||
when(pluginManager.getAvailable()).thenReturn(Collections.singletonList(plugin));
|
||||
when(collectionMapper.mapAvailable(Collections.singletonList(plugin))).thenReturn(new MockedResultDto());
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/available");
|
||||
request.accept(VndMediaType.PLUGIN_COLLECTION);
|
||||
@@ -105,16 +109,18 @@ class AvailablePluginResourceTest {
|
||||
@Test
|
||||
void getAvailablePlugin() throws UnsupportedEncodingException, URISyntaxException {
|
||||
PluginInformation pluginInformation = new PluginInformation();
|
||||
pluginInformation.setState(PluginState.AVAILABLE);
|
||||
pluginInformation.setName("pluginName");
|
||||
pluginInformation.setVersion("2.0.0");
|
||||
when(pluginManager.getAvailable()).thenReturn(Collections.singletonList(pluginInformation));
|
||||
|
||||
AvailablePlugin plugin = createPlugin(pluginInformation);
|
||||
|
||||
when(pluginManager.getAvailable("pluginName")).thenReturn(Optional.of(plugin));
|
||||
|
||||
PluginDto pluginDto = new PluginDto();
|
||||
pluginDto.setName("pluginName");
|
||||
when(mapper.map(pluginInformation)).thenReturn(pluginDto);
|
||||
when(mapper.map(plugin)).thenReturn(pluginDto);
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/available/pluginName/2.0.0");
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/available/pluginName");
|
||||
request.accept(VndMediaType.PLUGIN);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
@@ -126,17 +132,26 @@ class AvailablePluginResourceTest {
|
||||
|
||||
@Test
|
||||
void installPlugin() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.post("/v2/plugins/available/pluginName/2.0.0/install");
|
||||
MockHttpRequest request = MockHttpRequest.post("/v2/plugins/available/pluginName/install");
|
||||
request.accept(VndMediaType.PLUGIN);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
verify(pluginManager).install("pluginName:2.0.0");
|
||||
verify(pluginManager).install("pluginName");
|
||||
assertThat(HttpServletResponse.SC_OK).isEqualTo(response.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
private AvailablePlugin createPlugin() {
|
||||
return createPlugin(new PluginInformation());
|
||||
}
|
||||
|
||||
private AvailablePlugin createPlugin(PluginInformation pluginInformation) {
|
||||
AvailablePluginDescriptor descriptor = new AvailablePluginDescriptor(pluginInformation, new PluginCondition(), Collections.emptySet());
|
||||
return new AvailablePlugin(descriptor);
|
||||
}
|
||||
|
||||
@Nested
|
||||
class WithoutAuthorization {
|
||||
|
||||
@@ -156,7 +171,7 @@ class AvailablePluginResourceTest {
|
||||
|
||||
@Test
|
||||
void shouldNotGetAvailablePluginIfMissingPermission() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/available/pluginName/2.0.0");
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/available/pluginName");
|
||||
request.accept(VndMediaType.PLUGIN);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
@@ -166,7 +181,7 @@ class AvailablePluginResourceTest {
|
||||
@Test
|
||||
void shouldNotInstallPluginIfMissingPermission() throws URISyntaxException {
|
||||
ThreadContext.unbindSubject();
|
||||
MockHttpRequest request = MockHttpRequest.post("/v2/plugins/available/pluginName/2.0.0/install");
|
||||
MockHttpRequest request = MockHttpRequest.post("/v2/plugins/available/pluginName/install");
|
||||
request.accept(VndMediaType.PLUGIN);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
|
||||
@@ -16,11 +16,10 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.plugin.InstalledPlugin;
|
||||
import sonia.scm.plugin.InstalledPluginDescriptor;
|
||||
import sonia.scm.plugin.PluginInformation;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
import sonia.scm.plugin.PluginState;
|
||||
import sonia.scm.plugin.InstalledPlugin;
|
||||
import sonia.scm.plugin.PluginManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Provider;
|
||||
@@ -28,12 +27,12 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class InstalledPluginResourceTest {
|
||||
@@ -46,15 +45,15 @@ class InstalledPluginResourceTest {
|
||||
@Mock
|
||||
Provider<AvailablePluginResource> availablePluginResourceProvider;
|
||||
|
||||
@Mock
|
||||
private PluginLoader pluginLoader;
|
||||
|
||||
@Mock
|
||||
private PluginDtoCollectionMapper collectionMapper;
|
||||
|
||||
@Mock
|
||||
private PluginDtoMapper mapper;
|
||||
|
||||
@Mock
|
||||
private PluginManager pluginManager;
|
||||
|
||||
@InjectMocks
|
||||
InstalledPluginResource installedPluginResource;
|
||||
|
||||
@@ -86,9 +85,9 @@ class InstalledPluginResourceTest {
|
||||
|
||||
@Test
|
||||
void getInstalledPlugins() throws URISyntaxException, UnsupportedEncodingException {
|
||||
InstalledPlugin installedPlugin = new InstalledPlugin(null, null, null, null);
|
||||
when(pluginLoader.getInstalledPlugins()).thenReturn(Collections.singletonList(installedPlugin));
|
||||
when(collectionMapper.map(Collections.singletonList(installedPlugin))).thenReturn(new MockedResultDto());
|
||||
InstalledPlugin installedPlugin = createPlugin();
|
||||
when(pluginManager.getInstalled()).thenReturn(Collections.singletonList(installedPlugin));
|
||||
when(collectionMapper.mapInstalled(Collections.singletonList(installedPlugin))).thenReturn(new MockedResultDto());
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/installed");
|
||||
request.accept(VndMediaType.PLUGIN_COLLECTION);
|
||||
@@ -105,10 +104,9 @@ class InstalledPluginResourceTest {
|
||||
PluginInformation pluginInformation = new PluginInformation();
|
||||
pluginInformation.setVersion("2.0.0");
|
||||
pluginInformation.setName("pluginName");
|
||||
pluginInformation.setState(PluginState.INSTALLED);
|
||||
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, pluginInformation, null, null, false, null);
|
||||
InstalledPlugin installedPlugin = new InstalledPlugin(plugin, null, null, null);
|
||||
when(pluginLoader.getInstalledPlugins()).thenReturn(Collections.singletonList(installedPlugin));
|
||||
InstalledPlugin installedPlugin = createPlugin(pluginInformation);
|
||||
|
||||
when(pluginManager.getInstalled("pluginName")).thenReturn(Optional.of(installedPlugin));
|
||||
|
||||
PluginDto pluginDto = new PluginDto();
|
||||
pluginDto.setName("pluginName");
|
||||
@@ -125,6 +123,18 @@ class InstalledPluginResourceTest {
|
||||
}
|
||||
}
|
||||
|
||||
private InstalledPlugin createPlugin() {
|
||||
return createPlugin(new PluginInformation());
|
||||
}
|
||||
|
||||
private InstalledPlugin createPlugin(PluginInformation information) {
|
||||
InstalledPlugin plugin = mock(InstalledPlugin.class);
|
||||
InstalledPluginDescriptor descriptor = mock(InstalledPluginDescriptor.class);
|
||||
lenient().when(descriptor.getInformation()).thenReturn(information);
|
||||
lenient().when(plugin.getDescriptor()).thenReturn(descriptor);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Nested
|
||||
class WithoutAuthorization {
|
||||
|
||||
|
||||
@@ -4,13 +4,19 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.plugin.Plugin;
|
||||
import sonia.scm.plugin.PluginDescriptor;
|
||||
import sonia.scm.plugin.PluginInformation;
|
||||
import sonia.scm.plugin.PluginState;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.in;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class PluginDtoMapperTest {
|
||||
@@ -25,7 +31,8 @@ class PluginDtoMapperTest {
|
||||
void shouldMapInformation() {
|
||||
PluginInformation information = createPluginInformation();
|
||||
|
||||
PluginDto dto = mapper.map(information);
|
||||
PluginDto dto = new PluginDto();
|
||||
mapper.map(information, dto);
|
||||
|
||||
assertThat(dto.getName()).isEqualTo("scm-cas-plugin");
|
||||
assertThat(dto.getVersion()).isEqualTo("1.0.0");
|
||||
@@ -48,41 +55,51 @@ class PluginDtoMapperTest {
|
||||
|
||||
@Test
|
||||
void shouldAppendInstalledSelfLink() {
|
||||
PluginInformation information = createPluginInformation();
|
||||
information.setState(PluginState.INSTALLED);
|
||||
Plugin plugin = createPlugin(PluginState.INSTALLED);
|
||||
|
||||
PluginDto dto = mapper.map(information);
|
||||
PluginDto dto = mapper.map(plugin);
|
||||
assertThat(dto.getLinks().getLinkBy("self").get().getHref())
|
||||
.isEqualTo("https://hitchhiker.com/v2/plugins/installed/scm-cas-plugin");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAppendAvailableSelfLink() {
|
||||
PluginInformation information = createPluginInformation();
|
||||
information.setState(PluginState.AVAILABLE);
|
||||
Plugin plugin = createPlugin(PluginState.AVAILABLE);
|
||||
|
||||
PluginDto dto = mapper.map(information);
|
||||
PluginDto dto = mapper.map(plugin);
|
||||
assertThat(dto.getLinks().getLinkBy("self").get().getHref())
|
||||
.isEqualTo("https://hitchhiker.com/v2/plugins/available/scm-cas-plugin/1.0.0");
|
||||
.isEqualTo("https://hitchhiker.com/v2/plugins/available/scm-cas-plugin");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAppendInstallLink() {
|
||||
PluginInformation information = createPluginInformation();
|
||||
information.setState(PluginState.AVAILABLE);
|
||||
Plugin plugin = createPlugin(PluginState.AVAILABLE);
|
||||
|
||||
PluginDto dto = mapper.map(information);
|
||||
PluginDto dto = mapper.map(plugin);
|
||||
assertThat(dto.getLinks().getLinkBy("install").get().getHref())
|
||||
.isEqualTo("https://hitchhiker.com/v2/plugins/available/scm-cas-plugin/1.0.0/install");
|
||||
.isEqualTo("https://hitchhiker.com/v2/plugins/available/scm-cas-plugin/install");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnMiscellaneousIfCategoryIsNull() {
|
||||
PluginInformation information = createPluginInformation();
|
||||
information.setCategory(null);
|
||||
|
||||
PluginDto dto = mapper.map(information);
|
||||
Plugin plugin = createPlugin(information, PluginState.AVAILABLE);
|
||||
PluginDto dto = mapper.map(plugin);
|
||||
assertThat(dto.getCategory()).isEqualTo("Miscellaneous");
|
||||
}
|
||||
|
||||
private Plugin createPlugin(PluginState state) {
|
||||
return createPlugin(createPluginInformation(), state);
|
||||
}
|
||||
|
||||
private Plugin createPlugin(PluginInformation information, PluginState state) {
|
||||
Plugin plugin = Mockito.mock(Plugin.class);
|
||||
when(plugin.getState()).thenReturn(state);
|
||||
PluginDescriptor descriptor = mock(PluginDescriptor.class);
|
||||
when(descriptor.getInformation()).thenReturn(information);
|
||||
when(plugin.getDescriptor()).thenReturn(descriptor);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user