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