001/*
002 * (C) Copyright 2006-2014 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 */
018package org.nuxeo.connect.client.we;
019
020import java.util.Arrays;
021import java.util.List;
022
023import javax.ws.rs.GET;
024import javax.ws.rs.Path;
025import javax.ws.rs.PathParam;
026import javax.ws.rs.Produces;
027import javax.ws.rs.QueryParam;
028
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031import org.nuxeo.connect.connector.ConnectServerError;
032import org.nuxeo.connect.data.DownloadablePackage;
033import org.nuxeo.connect.data.DownloadingPackage;
034import org.nuxeo.connect.downloads.ConnectDownloadManager;
035import org.nuxeo.connect.packages.PackageManager;
036import org.nuxeo.connect.update.PackageState;
037import org.nuxeo.ecm.webengine.model.WebObject;
038import org.nuxeo.ecm.webengine.model.impl.DefaultObject;
039import org.nuxeo.runtime.api.Framework;
040
041/**
042 * Provides REST binding for {@link org.nuxeo.connect.update.Package} download management.
043 *
044 * @author <a href="mailto:td@nuxeo.com">Thierry Delprat</a>
045 */
046@WebObject(type = "downloadHandler")
047public class DownloadHandler extends DefaultObject {
048
049    protected static final Log log = LogFactory.getLog(DownloadHandler.class);
050
051    @GET
052    @Produces("text/plain")
053    @Path(value = "progress/{pkgId}")
054    public String getDownloadProgress(@PathParam("pkgId") String pkgId) {
055        DownloadingPackage pkg = getDownloadingPackage(pkgId);
056        if (pkg == null) {
057            return null;
058        }
059        return pkg.getDownloadProgress() + "";
060    }
061
062    @GET
063    @Produces("application/json")
064    @Path(value = "progressAsJSON")
065    public String getDownloadsProgress() {
066        ConnectDownloadManager cdm = Framework.getLocalService(ConnectDownloadManager.class);
067        List<DownloadingPackage> pkgs = cdm.listDownloadingPackages();
068        StringBuffer sb = new StringBuffer();
069        sb.append("[");
070        for (int i = 0; i < pkgs.size(); i++) {
071            if (i > 0) {
072                sb.append(",");
073            }
074            sb.append("{ \"pkgid\" : ");
075            sb.append("\"" + pkgs.get(i).getId() + "\",");
076            sb.append(" \"progress\" : ");
077            sb.append(pkgs.get(i).getDownloadProgress() + "}");
078        }
079        sb.append("]");
080        return sb.toString();
081    }
082
083    @GET
084    @Produces("text/html")
085    @Path(value = "progressPage/{pkgId}")
086    public Object getDownloadProgressPage(@PathParam("pkgId") String pkgId, @QueryParam("source") String source,
087            @QueryParam("install") Boolean install, @QueryParam("depCheck") Boolean depCheck,
088            @QueryParam("type") String pkgType, @QueryParam("onlyRemote") Boolean onlyRemote,
089            @QueryParam("filterOnPlatform") Boolean filterOnPlatform) {
090        DownloadablePackage pkg = getDownloadingPackage(pkgId);
091        boolean downloadOver = false;
092        // flag to start install after download
093        if (install == null) {
094            install = false;
095        }
096        if (depCheck == null) {
097            depCheck = true;
098        }
099        if (pkg == null) {
100            PackageManager pm = Framework.getLocalService(PackageManager.class);
101            pkg = pm.getPackage(pkgId);
102            if (pkg.getPackageState() != PackageState.DOWNLOADING) {
103                downloadOver = true;
104            }
105        }
106        return getView("downloadStarted").arg("pkg", pkg).arg("source", source).arg("over", downloadOver).arg(
107                "install", install).arg("depCheck", depCheck).arg("filterOnPlatform", filterOnPlatform.toString()).arg(
108                "type", pkgType.toString()).arg("onlyRemote", onlyRemote.toString());
109    }
110
111    protected DownloadingPackage getDownloadingPackage(String pkgId) {
112        ConnectDownloadManager cdm = Framework.getLocalService(ConnectDownloadManager.class);
113        List<DownloadingPackage> pkgs = cdm.listDownloadingPackages();
114        for (DownloadingPackage pkg : pkgs) {
115            if (pkg.getId().equals(pkgId)) {
116                return pkg;
117            }
118        }
119        return null;
120    }
121
122    @GET
123    @Produces("text/html")
124    @Path(value = "start/{pkgId}")
125    public Object startDownload(@PathParam("pkgId") String pkgId, @QueryParam("source") String source,
126            @QueryParam("install") Boolean install, @QueryParam("depCheck") Boolean depCheck,
127            @QueryParam("type") String pkgType, @QueryParam("onlyRemote") Boolean onlyRemote,
128            @QueryParam("filterOnPlatform") Boolean filterOnPlatform) {
129        PackageManager pm = Framework.getLocalService(PackageManager.class);
130        // flag to start install after download
131        if (install == null) {
132            install = false;
133        }
134        if (depCheck == null) {
135            depCheck = true;
136        }
137        if (!RequestHelper.isInternalLink(getContext())) {
138            DownloadablePackage pkg = pm.getPackage(pkgId);
139            return getView("confirmDownload").arg("pkg", pkg).arg("source", source);
140        }
141        try {
142            pm.download(pkgId);
143        } catch (ConnectServerError e) {
144            return getView("downloadError").arg("e", e);
145        }
146        return getView("downloadStarted").arg("pkg", getDownloadingPackage(pkgId)).arg("source", source).arg("over",
147                false).arg("install", install).arg("depCheck", depCheck).arg("filterOnPlatform",
148                filterOnPlatform.toString()).arg("type", pkgType.toString()).arg("onlyRemote", onlyRemote.toString());
149    }
150
151    @GET
152    @Produces("application/json")
153    @Path(value = "startDownloads")
154    public String startDownloads(@QueryParam("pkgList") String pkgList) {
155        if (RequestHelper.isInternalLink(getContext())) {
156            if (pkgList != null) {
157                String[] pkgs = pkgList.split("/");
158                PackageManager pm = Framework.getLocalService(PackageManager.class);
159                try {
160                    log.info("Starting download for packages " + Arrays.toString(pkgs));
161                    pm.download(Arrays.asList(pkgs));
162                } catch (ConnectServerError e) {
163                    log.error(e, e);
164                }
165                // here we generate a fake progress report so that if some
166                // download are very fast, they will still be visible on the
167                // client side
168                StringBuffer sb = new StringBuffer();
169                sb.append("[");
170                for (int i = 0; i < pkgs.length; i++) {
171                    if (i > 0) {
172                        sb.append(",");
173                    }
174                    sb.append("{ \"pkgid\" : ");
175                    sb.append("\"" + pkgs[i] + "\",");
176                    sb.append(" \"progress\" : 0}");
177                }
178                sb.append("]");
179                return sb.toString();
180            }
181        }
182        return "[]";
183    }
184
185    /**
186     * @since 5.6
187     */
188    @GET
189    @Path(value = "cancel/{pkgId}")
190    public Object cancelDownload(@PathParam("pkgId") String pkgId, @QueryParam("source") String source) {
191        PackageManager pm = Framework.getLocalService(PackageManager.class);
192        pm.cancelDownload(pkgId);
193        return redirect(getPrevious().getPath() + "/packages/" + source);
194    }
195
196}