Commits

Sebastian Sdorra committed 6fecb06

added api to install plugin packages

Comments (0)

Files changed (6)

scm-core/src/main/java/sonia/scm/io/ZipUnArchiver.java

 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
    * Method description
    *
    *
+   * @param inputStream
+   * @param outputDirectory
+   *
+   * @throws IOException
+   * @since 1.21
+   */
+  public void extractArchive(InputStream inputStream, File outputDirectory)
+    throws IOException
+  {
+    ZipInputStream input = new ZipInputStream(inputStream);
+
+    ZipEntry entry = input.getNextEntry();
+
+    while (entry != null)
+    {
+      extractEntry(outputDirectory, input, entry);
+      entry = input.getNextEntry();
+    }
+  }
+
+  /**
+   * Method description
+   *
+   *
    * @param archive
    * @param outputDirectory
    *
    */
   @Override
   protected void extractArchive(File archive, File outputDirectory)
-          throws IOException
+    throws IOException
   {
     if (logger.isDebugEnabled())
     {
       logger.debug("extract zip \"{}\" to \"{}\"", archive.getPath(),
-                   outputDirectory.getAbsolutePath());
+        outputDirectory.getAbsolutePath());
     }
 
-    ZipInputStream input = null;
+    InputStream input = null;
 
     try
     {
-      input = new ZipInputStream(new FileInputStream(archive));
-
-      ZipEntry entry = input.getNextEntry();
-
-      while (entry != null)
-      {
-        extractEntry(outputDirectory, input, entry);
-        entry = input.getNextEntry();
-      }
+      input = new FileInputStream(archive);
+      extractArchive(input, outputDirectory);
     }
     finally
     {
    * @throws IOException
    */
   private void extractEntry(File outputDirectory, ZipInputStream input,
-                            ZipEntry entry)
-          throws IOException
+    ZipEntry entry)
+    throws IOException
   {
     try
     {
    * @throws IOException
    */
   private void extractFile(ZipInputStream input, File outputFile)
-          throws IOException
+    throws IOException
   {
     FileOutputStream output = null;
 

scm-core/src/main/java/sonia/scm/plugin/PluginManager.java

 
 //~--- JDK imports ------------------------------------------------------------
 
+import java.io.IOException;
+import java.io.InputStream;
+
 import java.util.Collection;
 
 /**
   public void install(String id);
 
   /**
+   * Installs a plugin package from a inputstream.
+   *
+   *
+   * @param packageStream package input stream
+   *
+   * @throws IOException
+   * @since 1.21
+   */
+  public void installPackage(InputStream packageStream) throws IOException;
+
+  /**
    * Method description
    *
    *

scm-webapp/pom.xml

       </exclusions>
     </dependency>
     
+    <dependency>
+      <groupId>com.sun.jersey.contribs</groupId>
+      <artifactId>jersey-multipart</artifactId>
+      <version>${jersey.version}</version>
+    </dependency>
+    
     <!-- injection -->
 
     <dependency>
       <version>${aether.version}</version>
     </dependency>
     
+    <dependency>
+      <groupId>org.sonatype.aether</groupId>
+      <artifactId>aether-connector-file</artifactId>
+      <version>${aether.version}</version>
+    </dependency>
+    
     <!-- rest documentation -->
     
     <dependency>

scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java

 
 //~--- JDK imports ------------------------------------------------------------
 
+import com.sun.jersey.multipart.FormDataParam;
+
+import java.io.IOException;
+import java.io.InputStream;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
+import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
   //~--- methods --------------------------------------------------------------
 
   /**
+   * Installs a plugin from a package.<br />
+   * <br />
+   * <ul>
+   *   <li>200 success</li>
+   *   <li>500 internal server error</li>
+   * </ul>
+   *
+   *
+   *
+   * @param uploadedInputStream
+   * @return
+   *
+   * @throws IOException
+   */
+  @POST
+  @Path("install-package")
+  @Consumes(MediaType.MULTIPART_FORM_DATA)
+  public Response install(
+    @FormDataParam("package") InputStream uploadedInputStream)
+    throws IOException
+  {
+    pluginManager.installPackage(uploadedInputStream);
+
+    return Response.ok().build();
+  }
+
+  /**
    * Installs a plugin.<br />
    * <br />
    * <ul>

scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java

 import org.sonatype.aether.RepositorySystem;
 import org.sonatype.aether.collection.CollectRequest;
 import org.sonatype.aether.connector.async.AsyncRepositoryConnectorFactory;
+import org.sonatype.aether.connector.file.FileRepositoryConnectorFactory;
 import org.sonatype.aether.graph.Dependency;
 import org.sonatype.aether.graph.DependencyFilter;
 import org.sonatype.aether.graph.DependencyNode;
       DefaultArtifactDescriptorReader.class);
     locator.addService(RepositoryConnectorFactory.class,
       AsyncRepositoryConnectorFactory.class);
+    locator.addService(RepositoryConnectorFactory.class,
+      FileRepositoryConnectorFactory.class);
 
     return locator.getService(RepositorySystem.class);
   }

scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java

 
 //~--- non-JDK imports --------------------------------------------------------
 
+import com.google.common.collect.Sets;
+import com.google.common.io.Files;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import sonia.scm.cache.Cache;
 import sonia.scm.cache.CacheManager;
 import sonia.scm.config.ScmConfiguration;
+import sonia.scm.io.ZipUnArchiver;
 import sonia.scm.net.HttpClient;
 import sonia.scm.security.SecurityContext;
 import sonia.scm.util.AssertUtil;
 
 //~--- JDK imports ------------------------------------------------------------
 
+import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 
 import java.util.Map;
 import java.util.Set;
 
+import javax.xml.bind.JAXB;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
  */
 @Singleton
 public class DefaultPluginManager
-        implements PluginManager, ConfigChangedListener<ScmConfiguration>
+  implements PluginManager, ConfigChangedListener<ScmConfiguration>
 {
 
   /** Field description */
    * @param clientProvider
    */
   @Inject
-  public DefaultPluginManager(
-          SCMContextProvider context,
-          Provider<SecurityContext> securityContextProvicer,
-          ScmConfiguration configuration, PluginLoader pluginLoader,
-          CacheManager cacheManager, Provider<HttpClient> clientProvider)
+  public DefaultPluginManager(SCMContextProvider context,
+    Provider<SecurityContext> securityContextProvicer,
+    ScmConfiguration configuration, PluginLoader pluginLoader,
+    CacheManager cacheManager, Provider<HttpClient> clientProvider)
   {
     this.context = context;
     this.securityContextProvicer = securityContextProvicer;
     this.configuration = configuration;
     this.cache = cacheManager.getCache(String.class, PluginCenter.class,
-                                       CACHE_NAME);
+      CACHE_NAME);
     this.clientProvider = clientProvider;
     installedPlugins = new HashMap<String, Plugin>();
 
    * Method description
    *
    *
+   * @param packageStream
+   *
+   * @throws IOException
+   */
+  @Override
+  public void installPackage(InputStream packageStream) throws IOException
+  {
+    SecurityUtil.assertIsAdmin(securityContextProvicer);
+
+    File tempDirectory = Files.createTempDir();
+
+    try
+    {
+      new ZipUnArchiver().extractArchive(packageStream, tempDirectory);
+
+      Plugin plugin = JAXB.unmarshal(new File(tempDirectory, "plugin.xml"),
+                        Plugin.class);
+      
+      // TODO check conditions
+      
+
+      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
     for (PluginInformation info : getInstalled())
     {
       if (groupId.equals(info.getGroupId())
-          && artefactId.equals(info.getArtifactId()))
+        && artefactId.equals(info.getArtifactId()))
       {
         installed = info;
 
     }
 
     return url.replace("{version}", context.getVersion()).replace("{os}",
-                       os).replace("{arch}", arch);
+      os).replace("{arch}", arch);
   }
 
   /**
    * @param filter
    */
   private void filter(Set<PluginInformation> target,
-                      Collection<PluginInformation> source, PluginFilter filter)
+    Collection<PluginInformation> source, PluginFilter filter)
   {
     for (PluginInformation info : source)
     {
             if (pluginHandler == null)
             {
               pluginHandler = new AetherPluginHandler(this,
-                      SCMContext.getContext(), configuration);
+                SCMContext.getContext(), configuration);
             }
 
             pluginHandler.setPluginRepositories(center.getRepositories());
       PluginInformation installed = installedPlugin.getInformation();
 
       if (isSamePlugin(available, installed)
-          && (installed.getState() == PluginState.CORE))
+        && (installed.getState() == PluginState.CORE))
       {
         core = true;
 
    * @return
    */
   private boolean isNewer(PluginInformation available,
-                          PluginInformation installed)
+    PluginInformation installed)
   {
     boolean result = false;
     PluginVersion version = PluginVersion.createVersion(available.getVersion());
   private boolean isSamePlugin(PluginInformation p1, PluginInformation p2)
   {
     return p1.getGroupId().equals(p2.getGroupId())
-           && p1.getArtifactId().equals(p2.getArtifactId());
+      && p1.getArtifactId().equals(p2.getArtifactId());
   }
 
   //~--- fields ---------------------------------------------------------------