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.ArrayList;
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.lang.StringUtils;
030
031import org.nuxeo.connect.client.status.ConnectStatusHolder;
032import org.nuxeo.connect.client.ui.SharedPackageListingsSettings;
033import org.nuxeo.connect.client.vindoz.InstallAfterRestart;
034import org.nuxeo.connect.connector.http.ConnectUrlConfig;
035import org.nuxeo.connect.data.DownloadablePackage;
036import org.nuxeo.connect.data.DownloadingPackage;
037import org.nuxeo.connect.data.SubscriptionStatusType;
038import org.nuxeo.connect.packages.PackageManager;
039import org.nuxeo.connect.packages.dependencies.TargetPlatformFilterHelper;
040import org.nuxeo.connect.update.Package;
041import org.nuxeo.connect.update.PackageState;
042import org.nuxeo.connect.update.PackageType;
043import org.nuxeo.connect.update.PackageVisibility;
044import org.nuxeo.ecm.admin.runtime.PlatformVersionHelper;
045import org.nuxeo.ecm.webengine.model.WebObject;
046import org.nuxeo.ecm.webengine.model.impl.DefaultObject;
047import org.nuxeo.runtime.api.Framework;
048
049/**
050 * Provides REST binding for {@link Package} listings.
051 *
052 * @author <a href="mailto:td@nuxeo.com">Thierry Delprat</a>
053 */
054@WebObject(type = "packageListingProvider")
055public class PackageListingProvider extends DefaultObject {
056
057    /**
058     * @deprecated since 5.6
059     */
060    @Deprecated
061    public String getConnectBaseUrl() {
062        return ConnectUrlConfig.getBaseUrl();
063    }
064
065    /**
066     * @deprecated Since 5.6. Use {@link #getTargetPlatform(Boolean)} in original request to get only the wanted
067     *             packages instead of later filtering the whole list.
068     */
069    @Deprecated
070    protected List<DownloadablePackage> filterOnPlatform(List<DownloadablePackage> pkgs, Boolean filterOnPlatform) {
071        if (filterOnPlatform != Boolean.TRUE) {
072            return pkgs;
073        }
074        String targetPF = PlatformVersionHelper.getPlatformFilter();
075        if (targetPF == null) {
076            return pkgs;
077        } else {
078            List<DownloadablePackage> filteredPackages = new ArrayList<>();
079            for (DownloadablePackage pkg : pkgs) {
080                if (TargetPlatformFilterHelper.isCompatibleWithTargetPlatform(pkg,
081                        PlatformVersionHelper.getPlatformFilter())) {
082                    filteredPackages.add(pkg);
083                }
084            }
085            return filteredPackages;
086        }
087    }
088
089    @GET
090    @Produces("text/html")
091    @Path(value = "list")
092    public Object doList(@QueryParam("type") String pkgType, @QueryParam("filterOnPlatform") Boolean filterOnPlatform) {
093        PackageManager pm = Framework.getLocalService(PackageManager.class);
094        String targetPlatform = getTargetPlatform(filterOnPlatform);
095        List<DownloadablePackage> pkgs;
096        if (StringUtils.isBlank(pkgType)) {
097            pkgs = pm.listPackages(targetPlatform);
098        } else {
099            pkgs = pm.listPackages(PackageType.getByValue(pkgType), targetPlatform);
100        }
101        return getView("simpleListing").arg("pkgs", pm.sort(pkgs)).arg("showCommunityInfo", true).arg("source", "list").arg(
102                "filterOnPlatform", filterOnPlatform);
103    }
104
105    @GET
106    @Produces("text/html")
107    @Path(value = "updates")
108    public Object getUpdates(@QueryParam("type") String pkgType,
109            @QueryParam("filterOnPlatform") Boolean filterOnPlatform) {
110        PackageManager pm = Framework.getLocalService(PackageManager.class);
111        if (pkgType == null) {
112            pkgType = SharedPackageListingsSettings.instance().get("updates").getPackageTypeFilter();
113        }
114        if (filterOnPlatform == null) {
115            filterOnPlatform = SharedPackageListingsSettings.instance().get("updates").getPlatformFilter();
116        }
117        String targetPlatform = getTargetPlatform(filterOnPlatform);
118        List<DownloadablePackage> pkgs;
119        if (StringUtils.isBlank(pkgType)) {
120            pkgs = pm.listUpdatePackages(null, targetPlatform);
121        } else {
122            pkgs = pm.listUpdatePackages(PackageType.getByValue(pkgType), targetPlatform);
123        }
124        return getView("simpleListing").arg("pkgs", pm.sort(pkgs)).arg("showCommunityInfo", true).arg("source",
125                "updates").arg("filterOnPlatform", filterOnPlatform);
126    }
127
128    @GET
129    @Produces("text/html")
130    @Path(value = "private")
131    public Object getPrivate(@QueryParam("type") String pkgType,
132            @QueryParam("filterOnPlatform") Boolean filterOnPlatform) {
133        PackageManager pm = Framework.getLocalService(PackageManager.class);
134        if (pkgType == null) {
135            pkgType = SharedPackageListingsSettings.instance().get("private").getPackageTypeFilter();
136        }
137        if (filterOnPlatform == null) {
138            filterOnPlatform = SharedPackageListingsSettings.instance().get("private").getPlatformFilter();
139        }
140        String targetPlatform = getTargetPlatform(filterOnPlatform);
141        List<DownloadablePackage> pkgs;
142        if (StringUtils.isBlank(pkgType)) {
143            pkgs = pm.listPrivatePackages(targetPlatform);
144        } else {
145            pkgs = pm.listPrivatePackages(PackageType.getByValue(pkgType), targetPlatform);
146        }
147        return getView("simpleListing").arg("pkgs", pm.sort(pkgs)).arg("showCommunityInfo", true).arg("source",
148                "private").arg("filterOnPlatform", filterOnPlatform);
149    }
150
151    @GET
152    @Produces("text/html")
153    @Path(value = "local")
154    public Object getLocal(@QueryParam("type") String pkgType) {
155        PackageManager pm = Framework.getLocalService(PackageManager.class);
156        if (pkgType == null) {
157            pkgType = SharedPackageListingsSettings.instance().get("local").getPackageTypeFilter();
158        }
159        List<DownloadablePackage> pkgs;
160        if (StringUtils.isBlank(pkgType)) {
161            pkgs = pm.listLocalPackages();
162        } else {
163            pkgs = pm.listLocalPackages(PackageType.getByValue(pkgType));
164        }
165        return getView("simpleListing").arg("pkgs", pm.sort(pkgs)).arg("showCommunityInfo", false).arg("source",
166                "local");
167    }
168
169    @GET
170    @Produces("text/html")
171    @Path(value = "remote")
172    public Object getRemote(@QueryParam("type") String pkgType, @QueryParam("onlyRemote") Boolean onlyRemote,
173            @QueryParam("searchString") String searchString, @QueryParam("filterOnPlatform") Boolean filterOnPlatform) {
174        PackageManager pm = Framework.getLocalService(PackageManager.class);
175        if (pkgType == null) {
176            pkgType = SharedPackageListingsSettings.instance().get("remote").getPackageTypeFilter();
177        }
178        if (filterOnPlatform == null) {
179            filterOnPlatform = SharedPackageListingsSettings.instance().get("remote").getPlatformFilter();
180        }
181        if (onlyRemote == null) {
182            onlyRemote = SharedPackageListingsSettings.instance().get("remote").isOnlyRemote();
183        }
184        List<DownloadablePackage> pkgs;
185        String targetPlatform = getTargetPlatform(filterOnPlatform);
186        if (!StringUtils.isEmpty(searchString)) { // SEARCH IS NOT IMPLEMENTED
187            pkgs = pm.searchPackages(searchString);
188        } else if (onlyRemote) {
189            if (StringUtils.isBlank(pkgType)) {
190                pkgs = pm.listOnlyRemotePackages(targetPlatform);
191            } else {
192                pkgs = pm.listOnlyRemotePackages(PackageType.getByValue(pkgType), targetPlatform);
193            }
194        } else {
195            if (StringUtils.isBlank(pkgType)) {
196                pkgs = pm.listRemoteOrLocalPackages(targetPlatform);
197            } else {
198                pkgs = pm.listRemoteOrLocalPackages(PackageType.getByValue(pkgType), targetPlatform);
199            }
200        }
201        return getView("simpleListing").arg("pkgs", pm.sort(pkgs)).arg("showCommunityInfo", false).arg("source",
202                "remote").arg("filterOnPlatform", filterOnPlatform.toString()).arg("type", pkgType.toString()).arg(
203                "onlyRemote", onlyRemote.toString());
204    }
205
206    /**
207     * @param filterOnPlatform
208     * @return target platform if {@code filterOnPlatform==true} else null
209     * @since 5.6
210     */
211    private String getTargetPlatform(Boolean filterOnPlatform) {
212        if (filterOnPlatform != Boolean.TRUE) {
213            return null;
214        }
215        return PlatformVersionHelper.getPlatformFilter();
216    }
217
218    @GET
219    @Produces("text/html")
220    @Path(value = "studio")
221    public Object getStudio() {
222        PackageManager pm = Framework.getLocalService(PackageManager.class);
223        List<DownloadablePackage> pkgs = pm.listAllStudioRemoteOrLocalPackages();
224        List<DownloadablePackage> pkgsWithoutSnapshot = StudioSnapshotHelper.removeSnapshot(pkgs);
225        return getView("simpleListing").arg("pkgs", pm.sort(pkgsWithoutSnapshot)).arg("showCommunityInfo", false).arg(
226                "source", "studio");
227    }
228
229    public String getStateLabel(Package pkg) {
230        PackageState state = pkg.getPackageState();
231        switch (state) {
232        case REMOTE:
233        case DOWNLOADED:
234        case INSTALLED:
235            return state.getLabel();
236        case DOWNLOADING:
237            DownloadingPackage dpkg = (DownloadingPackage) pkg;
238            return state.getLabel() + " (" + dpkg.getDownloadProgress() + "%)";
239        case INSTALLING:
240            return "installation in progress";
241        case STARTED:
242            return "running";
243        case UNKNOWN:
244        default:
245            return "!?!";
246        }
247    }
248
249    public boolean canInstall(Package pkg) {
250        return PackageState.DOWNLOADED == pkg.getPackageState()
251                && !InstallAfterRestart.isMarkedForInstallAfterRestart(pkg.getId());
252    }
253
254    public boolean needsRestart(Package pkg) {
255        return InstallAfterRestart.isMarkedForInstallAfterRestart(pkg.getId())
256                || PackageState.INSTALLED == pkg.getPackageState()
257                || InstallAfterRestart.isMarkedForUninstallAfterRestart(pkg.getName());
258    }
259
260    public boolean canUnInstall(Package pkg) {
261        return pkg.getPackageState().isInstalled()
262                && !InstallAfterRestart.isMarkedForUninstallAfterRestart(pkg.getName());
263    }
264
265    /**
266     * @since 5.8
267     */
268    public boolean canUpgrade(Package pkg) {
269        return pkg.getPackageState().isInstalled() && pkg.getVersion().isSnapshot()
270                && !InstallAfterRestart.isMarkedForInstallAfterRestart(pkg.getName());
271    }
272
273    public boolean canRemove(Package pkg) {
274        return pkg.isLocal();
275    }
276
277    /**
278     * @since 5.6
279     */
280    public boolean canCancel(Package pkg) {
281        return PackageState.DOWNLOADING == pkg.getPackageState();
282    }
283
284    public boolean canDownload(Package pkg) {
285        return pkg.getPackageState() == PackageState.REMOTE
286                && (pkg.getType() == PackageType.STUDIO || pkg.getVisibility() == PackageVisibility.PUBLIC //
287                || (ConnectStatusHolder.instance().isRegistred() //
288                && ConnectStatusHolder.instance().getStatus().status() == SubscriptionStatusType.OK));
289    }
290
291    @GET
292    @Produces("text/html")
293    @Path(value = "details/{pkgId}")
294    public Object getDetails(@PathParam("pkgId") String pkgId) {
295        PackageManager pm = Framework.getLocalService(PackageManager.class);
296        DownloadablePackage pkg = pm.getPackage(pkgId);
297        if (pkg != null) {
298            return getView("pkgDetails").arg("pkg", pkg);
299        } else {
300            return getView("pkgNotFound").arg("pkgId", pkgId);
301        }
302    }
303
304    /**
305     * @since 5.6
306     * @return true if registration is required for download
307     */
308    public boolean registrationRequired(Package pkg) {
309        return pkg.getPackageState() == PackageState.REMOTE && pkg.getType() != PackageType.STUDIO
310                && pkg.getVisibility() != PackageVisibility.PUBLIC && (!ConnectStatusHolder.instance().isRegistred() //
311                || ConnectStatusHolder.instance().getStatus().status() != SubscriptionStatusType.OK);
312    }
313
314}