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