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