package org.motechproject.admin.bundles;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.osgi.framework.Bundle;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * This class is responsible for saving/removing bundle files. Bundles are currently stored in a specified
 * directory. Permanently uninstalling a bundle requires also its removal through this class. It is also responsible
 * for  saving new bundles coming either as a {@link MultipartFile}(UI) or an {@link InputStream}.
 */
@Component
public class BundleDirectoryManager {

    @Value("${user.home}/.motech/bundles")
    private String bundleDir;

    /**
     * Returns the directory used to store Motech bundles
     * @return the bundle directory
     */
    public String getBundleDir() {
        return bundleDir;
    }

    /**
     * Changes the directory used to store Motech bundles.
     * @param bundleDir the directory which is to be used for storing bundles.
     */
    public void setBundleDir(String bundleDir) {
        this.bundleDir = bundleDir;
    }

    /**
     * Saves a bundle from the given MultipartFile. The bundle is placed in the specified bundle directory.
     * The {@code MultipartFile} objects usually come from the UI(uploaded bundles).
     *
     * @param multipartFile the file representing the bundle.
     * @return the {@link File} created in the filesystem.
     * @throws IOException if it was unable to save the file.
     * @see #getBundleDir()
     * @see #setBundleDir(String)
     */
    public File saveBundleFile(MultipartFile multipartFile) throws IOException {
        String destFileName = multipartFile.getOriginalFilename();
        InputStream is = null;
        try {
            is = multipartFile.getInputStream();
            return saveBundleStreamToFile(destFileName, is);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    /**
     * Saves a bundle from the given {@link InputStream}. The bundle is placed in the specified bundle directory.
     * Since the inputstream does not contain a name, the name of the resultant file must also be provided.
     *
     * @param destFileName the name of destination file to which the bundle will be saved.
     * @param in the {@link InputStream} containing the bundle
     * @return the {@link File} created in the filesystem.
     * @throws IOException if it was unable to save the file.
     * @see #getBundleDir()
     * @see #setBundleDir(String)
     */
    public File saveBundleStreamToFile(String destFileName, InputStream in) throws IOException {
        File destFile = new File(bundleDir, destFileName);
        try (OutputStream os = FileUtils.openOutputStream(destFile)) {
            IOUtils.copy(in, os);
            return destFile;
        }
    }

    /**
     * Removes the given {@link Bundle} from the filesystem. The file to be removed is determined based on
     * the return value of {@link org.osgi.framework.Bundle#getLocation()} from the passed bundle.
     *
     * @param bundle the {@link Bundle} to be removed from the filesystem.
     * @return true if the bundle was removed, false otherwise.
     * @throws MalformedURLException if it was unable to create an {@link URL} to the bundle's location.
     */
    public boolean removeBundle(Bundle bundle) throws MalformedURLException {
        URL location = new URL(bundle.getLocation());

        File bundleFile = FileUtils.toFile(location);

        return FileUtils.deleteQuietly(bundleFile);
    }
}

@@ -124,37 +124,223 @@
 ort org.
-osgi.framework.Bundle
+motechproject.config.core.domain.BootstrapConfig;%0Aimport org.motechproject.config.service.ConfigurationService;%0Aimport org.osgi.framework.Bundle;%0Aimport org.springframework.beans.factory.annotation.Autowired
 ;%0Aimport
@@ -1046,16 +1046,87 @@
 ager %7B%0A%0A
+    @Autowired%0A    private ConfigurationService configurationService;%0A%0A
     @Val
@@ -1293,32 +1293,32 @@
 rectory%0A     */%0A
-
     public Strin
@@ -1332,24 +1332,293 @@
 ndleDir() %7B%0A
+        if (configurationService != null) %7B%0A            BootstrapConfig bootstrapConfig = configurationService.loadBootstrapConfig();%0A            if (bootstrapConfig != null) %7B%0A                return bootstrapConfig.getMotechDir() + %22/bundles%22;%0A            %7D%0A        %7D%0A
         retu
@@ -3435,25 +3435,28 @@
 ew File(
-b
+getB
 undleDir
 , destFi
@@ -3447,16 +3447,18 @@
 undleDir
+()
 , destFi

Make motech directory configurable