/*
* (C) Copyright 2010 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Anahide Tchertchian
*/
package org.nuxeo.ecm.platform.forms.layout.export;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetTypeConfiguration;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetTypeDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.impl.WidgetTypeDefinitionComparator;
import org.nuxeo.ecm.platform.forms.layout.api.service.LayoutStore;
import org.nuxeo.ecm.webengine.model.exceptions.WebResourceNotFoundException;
import org.nuxeo.ecm.webengine.model.view.TemplateView;
import org.nuxeo.runtime.api.Framework;
/**
* Exports and presents documentation about widget type definitions
*
* @author Anahide Tchertchian
* @since 5.4
*/
public class WidgetTypeResource {
protected final String category;
protected LayoutStore service;
protected final List<WidgetTypeDefinition> widgetTypes;
protected final Map<String, List<WidgetTypeDefinition>> widgetTypesByCat;
public WidgetTypeResource(String category) {
this.category = category;
service = Framework.getService(LayoutStore.class);
widgetTypes = service.getWidgetTypeDefinitions(category);
// sort so that order is deterministic
Collections.sort(widgetTypes, new WidgetTypeDefinitionComparator(true));
widgetTypesByCat = getWidgetTypesByCategory();
}
protected Map<String, List<WidgetTypeDefinition>> getWidgetTypesByCategory() {
Map<String, List<WidgetTypeDefinition>> cats = new HashMap<String, List<WidgetTypeDefinition>>();
List<WidgetTypeDefinition> unknownCatWidgets = new ArrayList<WidgetTypeDefinition>();
for (WidgetTypeDefinition wTypeDef : widgetTypes) {
List<String> categories = null;
WidgetTypeConfiguration conf = wTypeDef.getConfiguration();
if (conf != null) {
categories = conf.getCategories();
}
boolean added = false;
if (categories != null) {
for (String cat : categories) {
List<WidgetTypeDefinition> list = cats.get(cat);
if (list == null) {
list = new ArrayList<WidgetTypeDefinition>();
}
list.add(wTypeDef);
cats.put(cat, list);
added = true;
}
}
if (!added) {
unknownCatWidgets.add(wTypeDef);
}
}
if (!unknownCatWidgets.isEmpty()) {
cats.put("unknown", unknownCatWidgets);
}
// sort by category key
List<String> sortedKeys = new ArrayList<String>(cats.keySet());
Collections.sort(sortedKeys);
Map<String, List<WidgetTypeDefinition>> res = new LinkedHashMap<String, List<WidgetTypeDefinition>>();
for (String key : sortedKeys) {
res.put(key, cats.get(key));
}
return res;
}
/**
* Returns widget types definitions for given categories
* <p>
* If the category is null, the filter does not check the category. Widget types without a configuration are
* included if boolean 'all' is set to true. Mutliple categories are extracted from the query parameter by splitting
* on the space character.
* <p>
* If not null, the version parameter will exclude all widget types that did not exist before this version.
*/
@GET
@Path("widgetTypes")
public Object getWidgetTypeDefinitions(@Context HttpServletRequest request,
@QueryParam("categories") String categories, @QueryParam("version") String version,
@QueryParam("all") Boolean all) {
// TODO: refactor so that's cached
List<String> catsList = new ArrayList<String>();
if (categories != null) {
for (String cat : categories.split(" ")) {
catsList.add(cat);
}
}
WidgetTypeDefinitions res = new WidgetTypeDefinitions();
for (WidgetTypeDefinition def : widgetTypes) {
WidgetTypeConfiguration conf = def.getConfiguration();
if (!Boolean.TRUE.equals(all) && conf == null) {
continue;
}
if (version != null && conf != null) {
String confVersion = conf.getSinceVersion();
if (confVersion != null && isStriclyBeforeVersion(version, confVersion)) {
continue;
}
}
if (catsList != null && !catsList.isEmpty()) {
boolean hasCats = false;
if (conf != null) {
// filter on category
List<String> confCats = conf.getCategories();
if (confCats != null) {
hasCats = true;
for (String confCat : confCats) {
if (catsList.contains(confCat)) {
res.add(def);
break;
}
}
}
}
if (!hasCats && catsList.size() == 1 && catsList.contains("unknown")) {
res.add(def);
}
} else {
if (conf == null && !Boolean.TRUE.equals(all)) {
continue;
}
res.add(def);
}
}
return res;
}
protected boolean isStriclyBeforeVersion(String ref, String version) {
if (version == null || version.trim().length() == 0) {
return true;
}
String[] components1 = ref.split("\\.");
String[] components2 = version.split("\\.");
int length = Math.min(components1.length, components2.length);
for (int i = 0; i < length; i++) {
int result = Integer.compare(Integer.valueOf(components1[i]), Integer.valueOf(components2[i]));
if (result != 0) {
return result < 0;
}
}
return components1.length < components2.length;
}
/**
* Returns widget types definitions for given category.
* <p>
* If the category is null, the filter does not check the category. Widget types without a configuration are
* included if boolean 'all' is set to true.
* <p>
* If not null, the version parameter will exclude all widget types that did not exist before this version.
*/
@GET
@Path("widgetTypes/{category}")
public Object getWidgetTypeDefinitionsForCategory(@Context HttpServletRequest request,
@PathParam("category") String category, @QueryParam("version") String version,
@QueryParam("all") Boolean all) {
return getWidgetTypeDefinitions(request, category, version, all);
}
@GET
@Path("widgetType/{name}")
public Object getWidgetTypeDefinition(@Context HttpServletRequest request, @PathParam("name") String name) {
WidgetTypeDefinition def = service.getWidgetTypeDefinition(category, name);
if (def != null) {
return def;
} else {
return Response.status(401).build();
}
}
public TemplateView getTemplate(@Context UriInfo uriInfo) {
return getTemplate("widget-types.ftl", uriInfo);
}
@GET
@Path("wiki")
public Object getWikiDocumentation(@Context UriInfo uriInfo) {
return getTemplate("widget-types-wiki.ftl", uriInfo);
}
protected List<String> getNuxeoVersions() {
if ("jsf".equals(category) || "jsfAction".equals(category)) {
return Arrays.asList("5.8", "6.0", "7.10");
}
return Collections.emptyList();
}
protected List<String> getStudioCategories() {
return Arrays.asList("aggregates", "decoration", "dev", "document", "listing", "search", "standalone",
"summary", "tab_designer");
}
protected TemplateView getTemplate(String name, UriInfo uriInfo) {
String baseURL = uriInfo.getAbsolutePath().toString();
if (!baseURL.endsWith("/")) {
baseURL += "/";
}
TemplateView tv = new TemplateView(this, name);
tv.arg("categories", widgetTypesByCat);
tv.arg("nuxeoVersions", getNuxeoVersions());
tv.arg("widgetTypeCategory", category);
tv.arg("widgetTypes", widgetTypes);
tv.arg("studioCategories", StringUtils.join(getStudioCategories(), " "));
tv.arg("baseURL", baseURL);
return tv;
}
@GET
public Object doGet(@QueryParam("widgetType") String widgetTypeName, @Context UriInfo uriInfo) {
if (widgetTypeName == null) {
return getTemplate(uriInfo);
} else {
WidgetTypeDefinition wType = service.getWidgetTypeDefinition(category, widgetTypeName);
if (wType == null) {
throw new WebResourceNotFoundException("No widget type found with name: " + widgetTypeName);
}
TemplateView tpl = getTemplate(uriInfo);
tpl.arg("widgetType", wType);
return tpl;
}
}
public String getWidgetTypeLabel(WidgetTypeDefinition wTypeDef) {
if (wTypeDef != null) {
WidgetTypeConfiguration conf = wTypeDef.getConfiguration();
if (conf != null) {
return conf.getTitle();
}
return wTypeDef.getName();
}
return null;
}
public String getWidgetTypeDescription(WidgetTypeDefinition wTypeDef) {
if (wTypeDef != null) {
WidgetTypeConfiguration conf = wTypeDef.getConfiguration();
if (conf != null) {
return conf.getDescription();
}
}
return null;
}
public List<String> getWidgetTypeCategories(WidgetTypeDefinition wTypeDef) {
if (wTypeDef != null) {
WidgetTypeConfiguration conf = wTypeDef.getConfiguration();
if (conf != null) {
return conf.getCategories();
}
}
return null;
}
public String getWidgetTypeCategoriesAsString(WidgetTypeDefinition wTypeDef) {
List<String> categories = getWidgetTypeCategories(wTypeDef);
if (categories == null) {
return "";
} else {
return StringUtils.join(categories, ", ");
}
}
}