001/*
002 * (C) Copyright 2010 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.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 *     Anahide Tchertchian
016 */
017package org.nuxeo.ecm.platform.forms.layout.export;
018
019import java.util.ArrayList;
020import java.util.Arrays;
021import java.util.Collections;
022import java.util.HashMap;
023import java.util.LinkedHashMap;
024import java.util.List;
025import java.util.Map;
026
027import javax.servlet.http.HttpServletRequest;
028import javax.ws.rs.GET;
029import javax.ws.rs.Path;
030import javax.ws.rs.PathParam;
031import javax.ws.rs.QueryParam;
032import javax.ws.rs.core.Context;
033import javax.ws.rs.core.Response;
034import javax.ws.rs.core.UriInfo;
035
036import org.apache.commons.lang.StringUtils;
037import org.nuxeo.ecm.platform.forms.layout.api.WidgetTypeConfiguration;
038import org.nuxeo.ecm.platform.forms.layout.api.WidgetTypeDefinition;
039import org.nuxeo.ecm.platform.forms.layout.api.impl.WidgetTypeDefinitionComparator;
040import org.nuxeo.ecm.platform.forms.layout.api.service.LayoutStore;
041import org.nuxeo.ecm.webengine.model.exceptions.WebResourceNotFoundException;
042import org.nuxeo.ecm.webengine.model.view.TemplateView;
043import org.nuxeo.runtime.api.Framework;
044
045/**
046 * Exports and presents documentation about widget type definitions
047 *
048 * @author Anahide Tchertchian
049 * @since 5.4
050 */
051public class WidgetTypeResource {
052
053    protected final String category;
054
055    protected LayoutStore service;
056
057    protected final List<WidgetTypeDefinition> widgetTypes;
058
059    protected final Map<String, List<WidgetTypeDefinition>> widgetTypesByCat;
060
061    public WidgetTypeResource(String category) {
062        this.category = category;
063        service = Framework.getService(LayoutStore.class);
064        widgetTypes = service.getWidgetTypeDefinitions(category);
065        // sort so that order is deterministic
066        Collections.sort(widgetTypes, new WidgetTypeDefinitionComparator(true));
067        widgetTypesByCat = getWidgetTypesByCategory();
068    }
069
070    protected Map<String, List<WidgetTypeDefinition>> getWidgetTypesByCategory() {
071        Map<String, List<WidgetTypeDefinition>> cats = new HashMap<String, List<WidgetTypeDefinition>>();
072        List<WidgetTypeDefinition> unknownCatWidgets = new ArrayList<WidgetTypeDefinition>();
073        for (WidgetTypeDefinition wTypeDef : widgetTypes) {
074            List<String> categories = null;
075            WidgetTypeConfiguration conf = wTypeDef.getConfiguration();
076            if (conf != null) {
077                categories = conf.getCategories();
078            }
079            boolean added = false;
080            if (categories != null) {
081                for (String cat : categories) {
082                    List<WidgetTypeDefinition> list = cats.get(cat);
083                    if (list == null) {
084                        list = new ArrayList<WidgetTypeDefinition>();
085                    }
086                    list.add(wTypeDef);
087                    cats.put(cat, list);
088                    added = true;
089                }
090            }
091            if (!added) {
092                unknownCatWidgets.add(wTypeDef);
093            }
094        }
095        if (!unknownCatWidgets.isEmpty()) {
096            cats.put("unknown", unknownCatWidgets);
097        }
098        // sort by category key
099        List<String> sortedKeys = new ArrayList<String>(cats.keySet());
100        Collections.sort(sortedKeys);
101        Map<String, List<WidgetTypeDefinition>> res = new LinkedHashMap<String, List<WidgetTypeDefinition>>();
102        for (String key : sortedKeys) {
103            res.put(key, cats.get(key));
104        }
105        return res;
106    }
107
108    /**
109     * Returns widget types definitions for given categories
110     * <p>
111     * If the category is null, the filter does not check the category. Widget types without a configuration are
112     * included if boolean 'all' is set to true. Mutliple categories are extracted from the query parameter by splitting
113     * on the space character.
114     * <p>
115     * If not null, the version parameter will exclude all widget types that did not exist before this version.
116     */
117    @GET
118    @Path("widgetTypes")
119    public Object getWidgetTypeDefinitions(@Context HttpServletRequest request,
120            @QueryParam("categories") String categories, @QueryParam("version") String version,
121            @QueryParam("all") Boolean all) {
122        // TODO: refactor so that's cached
123        List<String> catsList = new ArrayList<String>();
124        if (categories != null) {
125            for (String cat : categories.split(" ")) {
126                catsList.add(cat);
127            }
128        }
129        WidgetTypeDefinitions res = new WidgetTypeDefinitions();
130        for (WidgetTypeDefinition def : widgetTypes) {
131            WidgetTypeConfiguration conf = def.getConfiguration();
132            if (!Boolean.TRUE.equals(all) && conf == null) {
133                continue;
134            }
135            if (version != null && conf != null) {
136                String confVersion = conf.getSinceVersion();
137                if (confVersion != null && version.compareTo(confVersion) < 0) {
138                    continue;
139                }
140            }
141            if (catsList != null && !catsList.isEmpty()) {
142                boolean hasCats = false;
143                if (conf != null) {
144                    // filter on category
145                    List<String> confCats = conf.getCategories();
146                    if (confCats != null) {
147                        hasCats = true;
148                        if (confCats.containsAll(catsList)) {
149                            res.add(def);
150                        }
151                    }
152                }
153                if (!hasCats && catsList.size() == 1 && catsList.contains("unknown")) {
154                    res.add(def);
155                }
156            } else {
157                if (conf == null && !Boolean.TRUE.equals(all)) {
158                    continue;
159                }
160                res.add(def);
161            }
162        }
163        return res;
164    }
165
166    /**
167     * Returns widget types definitions for given category.
168     * <p>
169     * If the category is null, the filter does not check the category. Widget types without a configuration are
170     * included if boolean 'all' is set to true.
171     * <p>
172     * If not null, the version parameter will exclude all widget types that did not exist before this version.
173     */
174    @GET
175    @Path("widgetTypes/{category}")
176    public Object getWidgetTypeDefinitionsForCategory(@Context HttpServletRequest request,
177            @PathParam("category") String category, @QueryParam("version") String version,
178            @QueryParam("all") Boolean all) {
179        return getWidgetTypeDefinitions(request, category, version, all);
180    }
181
182    @GET
183    @Path("widgetType/{name}")
184    public Object getWidgetTypeDefinition(@Context HttpServletRequest request, @PathParam("name") String name) {
185        WidgetTypeDefinition def = service.getWidgetTypeDefinition(category, name);
186        if (def != null) {
187            return def;
188        } else {
189            return Response.status(401).build();
190        }
191    }
192
193    public TemplateView getTemplate(@Context UriInfo uriInfo) {
194        return getTemplate("widget-types.ftl", uriInfo);
195    }
196
197    @GET
198    @Path("wiki")
199    public Object getWikiDocumentation(@Context UriInfo uriInfo) {
200        return getTemplate("widget-types-wiki.ftl", uriInfo);
201    }
202
203    protected List<String> getNuxeoVersions() {
204        if ("jsf".equals(category)) {
205            return Arrays.asList("5.6", "5.8", "6.0");
206        } else if ("jsfAction".equals(category)) {
207            return Arrays.asList("5.8", "6.0");
208        }
209        return Collections.emptyList();
210    }
211
212    protected TemplateView getTemplate(String name, UriInfo uriInfo) {
213        String baseURL = uriInfo.getAbsolutePath().toString();
214        if (!baseURL.endsWith("/")) {
215            baseURL += "/";
216        }
217        TemplateView tv = new TemplateView(this, name);
218        tv.arg("categories", widgetTypesByCat);
219        tv.arg("nuxeoVersions", getNuxeoVersions());
220        tv.arg("widgetTypeCategory", category);
221        tv.arg("widgetTypes", widgetTypes);
222        tv.arg("baseURL", baseURL);
223        return tv;
224    }
225
226    @GET
227    public Object doGet(@QueryParam("widgetType") String widgetTypeName, @Context UriInfo uriInfo) {
228        if (widgetTypeName == null) {
229            return getTemplate(uriInfo);
230        } else {
231            WidgetTypeDefinition wType = service.getWidgetTypeDefinition(category, widgetTypeName);
232            if (wType == null) {
233                throw new WebResourceNotFoundException("No widget type found with name: " + widgetTypeName);
234            }
235            TemplateView tpl = getTemplate(uriInfo);
236            tpl.arg("widgetType", wType);
237            return tpl;
238        }
239    }
240
241    public String getWidgetTypeLabel(WidgetTypeDefinition wTypeDef) {
242        if (wTypeDef != null) {
243            WidgetTypeConfiguration conf = wTypeDef.getConfiguration();
244            if (conf != null) {
245                return conf.getTitle();
246            }
247            return wTypeDef.getName();
248        }
249        return null;
250    }
251
252    public String getWidgetTypeDescription(WidgetTypeDefinition wTypeDef) {
253        if (wTypeDef != null) {
254            WidgetTypeConfiguration conf = wTypeDef.getConfiguration();
255            if (conf != null) {
256                return conf.getDescription();
257            }
258        }
259        return null;
260    }
261
262    public List<String> getWidgetTypeCategories(WidgetTypeDefinition wTypeDef) {
263        if (wTypeDef != null) {
264            WidgetTypeConfiguration conf = wTypeDef.getConfiguration();
265            if (conf != null) {
266                return conf.getCategories();
267            }
268        }
269        return null;
270    }
271
272    public String getWidgetTypeCategoriesAsString(WidgetTypeDefinition wTypeDef) {
273        List<String> categories = getWidgetTypeCategories(wTypeDef);
274        if (categories == null) {
275            return "";
276        } else {
277            return StringUtils.join(categories, ", ");
278        }
279    }
280
281}