/*
* (C) Copyright 2006-2016 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:
* <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
*/
package org.nuxeo.ecm.platform.forms.layout.service;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.TagConfig;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.platform.forms.layout.api.BuiltinModes;
import org.nuxeo.ecm.platform.forms.layout.api.BuiltinWidgetModes;
import org.nuxeo.ecm.platform.forms.layout.api.FieldDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.Layout;
import org.nuxeo.ecm.platform.forms.layout.api.LayoutDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.LayoutRow;
import org.nuxeo.ecm.platform.forms.layout.api.LayoutRowDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.LayoutTypeConfiguration;
import org.nuxeo.ecm.platform.forms.layout.api.LayoutTypeDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.Widget;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetReference;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetType;
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.converters.LayoutConversionContext;
import org.nuxeo.ecm.platform.forms.layout.api.converters.LayoutDefinitionConverter;
import org.nuxeo.ecm.platform.forms.layout.api.converters.WidgetDefinitionConverter;
import org.nuxeo.ecm.platform.forms.layout.api.exceptions.LayoutException;
import org.nuxeo.ecm.platform.forms.layout.api.exceptions.WidgetException;
import org.nuxeo.ecm.platform.forms.layout.api.impl.LayoutImpl;
import org.nuxeo.ecm.platform.forms.layout.api.impl.LayoutRowComparator;
import org.nuxeo.ecm.platform.forms.layout.api.impl.LayoutRowImpl;
import org.nuxeo.ecm.platform.forms.layout.api.impl.WidgetDefinitionImpl;
import org.nuxeo.ecm.platform.forms.layout.api.impl.WidgetImpl;
import org.nuxeo.ecm.platform.forms.layout.api.impl.WidgetReferenceImpl;
import org.nuxeo.ecm.platform.forms.layout.core.service.AbstractLayoutManager;
import org.nuxeo.ecm.platform.forms.layout.core.service.LayoutStoreImpl;
import org.nuxeo.ecm.platform.forms.layout.descriptors.LayoutDescriptor;
import org.nuxeo.ecm.platform.forms.layout.descriptors.LayoutTypeDescriptor;
import org.nuxeo.ecm.platform.forms.layout.descriptors.WidgetDescriptor;
import org.nuxeo.ecm.platform.forms.layout.descriptors.WidgetTypeDescriptor;
import org.nuxeo.ecm.platform.forms.layout.facelets.RenderVariables;
import org.nuxeo.ecm.platform.forms.layout.facelets.WidgetTypeHandler;
import org.nuxeo.ecm.platform.forms.layout.facelets.plugins.TemplateWidgetTypeHandler;
import org.nuxeo.ecm.platform.forms.layout.functions.LayoutFunctions;
import org.nuxeo.ecm.platform.ui.web.util.ComponentTagUtils;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.model.ComponentInstance;
import org.nuxeo.runtime.model.ComponentName;
import com.sun.faces.facelets.el.VariableMapperWrapper;
/**
* Layout service implementation.
*
* @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
*/
public class WebLayoutManagerImpl extends AbstractLayoutManager implements WebLayoutManager {
public static final ComponentName NAME = new ComponentName(WebLayoutManagerImpl.class.getName());
private static final Log log = LogFactory.getLog(WebLayoutManagerImpl.class);
private static final long serialVersionUID = 1L;
public static final String WIDGET_TYPES_EP_NAME = LayoutStoreImpl.WIDGET_TYPES_EP_NAME;
/**
* @since 6.0
*/
public static final String LAYOUT_TYPES_EP_NAME = LayoutStoreImpl.LAYOUT_TYPES_EP_NAME;
public static final String WIDGETS_EP_NAME = LayoutStoreImpl.WIDGETS_EP_NAME;
public static final String LAYOUTS_EP_NAME = LayoutStoreImpl.LAYOUTS_EP_NAME;
public static final String PROPS_REF_EP_NAME = "disabledPropertyRefs";
protected DisabledPropertyRefRegistry disabledPropertyRefsReg;
// Runtime component API
public WebLayoutManagerImpl() {
super();
disabledPropertyRefsReg = new DisabledPropertyRefRegistry();
}
@Override
public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
if (extensionPoint.equals(WIDGET_TYPES_EP_NAME)) {
registerWidgetType(((WidgetTypeDescriptor) contribution).getWidgetTypeDefinition());
} else if (extensionPoint.equals(LAYOUT_TYPES_EP_NAME)) {
registerLayoutType(((LayoutTypeDescriptor) contribution).getLayoutTypeDefinition());
} else if (extensionPoint.equals(LAYOUTS_EP_NAME)) {
registerLayout(((LayoutDescriptor) contribution).getLayoutDefinition());
} else if (extensionPoint.equals(WIDGETS_EP_NAME)) {
registerWidget(((WidgetDescriptor) contribution).getWidgetDefinition());
} else if (extensionPoint.equals(PROPS_REF_EP_NAME)) {
registerDisabledPropertyRef(((DisabledPropertyRefDescriptor) contribution));
} else {
log.error(String.format("Unknown extension point '%s', can't register !", extensionPoint));
}
}
@Override
public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
if (extensionPoint.equals(WIDGET_TYPES_EP_NAME)) {
unregisterWidgetType(((WidgetTypeDescriptor) contribution).getWidgetTypeDefinition());
} else if (extensionPoint.equals(LAYOUT_TYPES_EP_NAME)) {
unregisterLayoutType(((LayoutTypeDescriptor) contribution).getLayoutTypeDefinition());
} else if (extensionPoint.equals(LAYOUTS_EP_NAME)) {
unregisterLayout(((LayoutDescriptor) contribution).getLayoutDefinition());
} else if (extensionPoint.equals(WIDGETS_EP_NAME)) {
unregisterWidget(((WidgetDescriptor) contribution).getWidgetDefinition());
} else if (extensionPoint.equals(PROPS_REF_EP_NAME)) {
unregisterDisabledPropertyRef(((DisabledPropertyRefDescriptor) contribution));
} else {
log.error(String.format("Unknown extension point '%s', can't unregister !", extensionPoint));
}
}
// specific API (depends on JSF impl)
@Override
public String getDefaultStoreCategory() {
return JSF_CATEGORY;
}
@Override
public WidgetTypeHandler getWidgetTypeHandler(TagConfig config, String typeCategory, String typeName)
throws WidgetException {
if (StringUtils.isBlank(typeCategory)) {
typeCategory = getDefaultStoreCategory();
}
WidgetType type = getLayoutStore().getWidgetType(typeCategory, typeName);
if (type == null) {
return null;
}
WidgetTypeHandler handler;
Class<?> klass = type.getWidgetTypeClass();
if (klass == null) {
// implicit handler is the "template" one
handler = new TemplateWidgetTypeHandler(config);
} else {
try {
Constructor<?> ctor = klass.getDeclaredConstructor(TagConfig.class);
ctor.setAccessible(true);
handler = (WidgetTypeHandler) ctor.newInstance(config);
} catch (ReflectiveOperationException e) {
log.error("Caught error when instanciating widget type handler", e);
return null;
}
}
handler.setProperties(type.getProperties());
return handler;
}
@Override
public WidgetTypeHandler getWidgetTypeHandler(TagConfig config, Widget widget) throws WidgetException {
if (widget == null) {
return null;
}
WidgetTypeHandler handler = getWidgetTypeHandler(config, widget.getTypeCategory(), widget.getType());
if (handler != null) {
handler.setWidget(widget);
}
return handler;
}
/**
* Evaluates an EL expression in given context.
* <p>
* If the expression resolves to an EL expression, evaluate it again this is useful when retrieving the expression
* from a configuration file.
* <p>
* If given context is null, do no try to evaluate it and return the expression itself.
*
* @param context the facelet context.
* @param expression the string expression.
*/
protected static Object evaluateExpression(FaceletContext context, String expression) {
if (expression == null) {
return null;
}
if (context == null) {
return expression;
}
Object value = ComponentTagUtils.resolveElExpression(context, expression);
if (value != null && value instanceof String) {
// evaluate a second time in case it's another EL expression
value = ComponentTagUtils.resolveElExpression(context, (String) value);
}
return value;
}
/**
* Evaluates an expression to a boolean value.
*/
protected static Boolean getBooleanValue(FaceletContext context, String expression) {
Object value = evaluateExpression(context, expression);
if (value instanceof Boolean) {
return (Boolean) value;
} else if (value == null || value instanceof String) {
return Boolean.valueOf((String) value);
} else {
log.error("Could not get boolean value for '" + value + "' in expression '" + expression + "'");
return Boolean.FALSE;
}
}
/**
* Evaluates an expression to a string value.
*/
protected static String getStringValue(FaceletContext context, String expression) {
Object value = evaluateExpression(context, expression);
if (value == null || value instanceof String) {
return (String) value;
} else {
log.error("Could not get string value for '" + value + "' in expression '" + expression + "'");
return null;
}
}
protected static String getModeFromLayoutMode(FaceletContext context, WidgetDefinition wDef, String layoutMode) {
String wMode = getStringValue(context, wDef.getMode(layoutMode));
if (wMode == null) {
wMode = BuiltinModes.getWidgetModeFromLayoutMode(layoutMode);
}
return wMode;
}
@Override
public Widget getWidget(FaceletContext ctx, String widgetName, String widgetCategory, String layoutMode,
String valueName, String layoutName) {
WidgetReference widgetRef = new WidgetReferenceImpl(widgetCategory, widgetName);
WidgetDefinition wDef = lookupWidget(widgetRef);
return getWidget(ctx, null, null, layoutName, null, wDef, widgetCategory, layoutMode, valueName, 0);
}
@Override
public Widget getWidget(FaceletContext ctx, WidgetDefinition wDef, String layoutMode, String valueName,
String layoutName) {
return getWidget(ctx, null, null, layoutName, null, wDef, getDefaultStoreCategory(), layoutMode, valueName, 0);
}
@Override
public Widget getWidget(FaceletContext ctx, LayoutConversionContext lctx, String conversionCat,
WidgetDefinition widgetDef, String layoutMode, String valueName, String layoutName) {
return getWidget(ctx, null, null, layoutName, null, widgetDef, getDefaultStoreCategory(), layoutMode,
valueName, 0);
}
/**
* Computes a widget from a definition for a mode in a given context.
* <p>
* If the widget is configured not to be rendered in the given mode, returns null.
* <p>
* Sub widgets are also computed recursively.
*/
@SuppressWarnings("deprecation")
protected Widget getWidget(FaceletContext context, LayoutConversionContext lctx, String conversionCat,
String layoutName, LayoutDefinition layoutDef, WidgetDefinition widgetDefinition, String widgetCategory,
String layoutMode, String valueName, int level) {
if (widgetDefinition == null) {
return null;
}
WidgetDefinition wDef = widgetDefinition.clone();
if (lctx != null && !StringUtils.isBlank(conversionCat)) {
List<WidgetDefinitionConverter> lcs = getLayoutStore().getWidgetConverters(conversionCat);
for (WidgetDefinitionConverter wc : lcs) {
wDef = wc.getWidgetDefinition(wDef, lctx);
}
}
VariableMapper orig = null;
// avoid variable mapper changes if context is null for tests
if (context != null) {
// expose widget mode so that it can be used in a mode el
// expression
orig = context.getVariableMapper();
VariableMapper vm = new VariableMapperWrapper(orig);
context.setVariableMapper(vm);
ExpressionFactory eFactory = context.getExpressionFactory();
ValueExpression modeVe = eFactory.createValueExpression(layoutMode, String.class);
vm.setVariable(RenderVariables.globalVariables.mode.name(), modeVe);
}
String wMode = getModeFromLayoutMode(context, wDef, layoutMode);
if (context != null) {
context.setVariableMapper(orig);
}
if (BuiltinWidgetModes.HIDDEN.equals(wMode)) {
return null;
}
List<Widget> subWidgets = new ArrayList<>();
WidgetDefinition[] swDefs = wDef.getSubWidgetDefinitions();
if (swDefs != null) {
for (WidgetDefinition swDef : swDefs) {
Widget subWidget = getWidget(context, lctx, conversionCat, layoutName, layoutDef, swDef,
widgetCategory, wMode, valueName, level + 1);
if (subWidget != null) {
subWidgets.add(subWidget);
}
}
}
WidgetReference[] swRefs = wDef.getSubWidgetReferences();
if (swRefs != null) {
for (WidgetReference swRef : swRefs) {
String cat = swRef.getCategory();
if (StringUtils.isBlank(cat)) {
cat = widgetCategory;
}
WidgetDefinition swDef = lookupWidget(layoutDef, new WidgetReferenceImpl(cat, swRef.getName()));
if (swDef == null) {
log.error("Widget '" + swRef.getName() + "' not found in layout " + layoutName);
} else {
Widget subWidget = getWidget(context, lctx, conversionCat, layoutName, layoutDef, swDef, cat,
wMode, valueName, level + 1);
if (subWidget != null) {
subWidgets.add(subWidget);
}
}
}
}
boolean required = getBooleanValue(context, wDef.getRequired(layoutMode, wMode)).booleanValue();
String wType = wDef.getType();
String wTypeCat = wDef.getTypeCategory();
// fill default property and control values from the widget definition
Map<String, Serializable> props = new HashMap<>();
Map<String, Serializable> controls = new HashMap<>();
String actualWTypeCat = getStoreCategory(wTypeCat);
WidgetTypeDefinition def = getLayoutStore().getWidgetTypeDefinition(actualWTypeCat, wType);
WidgetTypeConfiguration conf = def != null ? def.getConfiguration() : null;
if (conf != null) {
Map<String, Serializable> defaultProps = conf.getDefaultPropertyValues(wMode);
if (defaultProps != null && !defaultProps.isEmpty()) {
props.putAll(defaultProps);
}
Map<String, Serializable> defaultControls = conf.getDefaultControlValues(wMode);
if (defaultControls != null && !defaultControls.isEmpty()) {
controls.putAll(defaultControls);
}
}
props.putAll(wDef.getProperties(layoutMode, wMode));
controls.putAll(wDef.getControls(layoutMode, wMode));
WidgetImpl widget = new WidgetImpl(layoutName, wDef.getName(), wMode, wType, valueName,
wDef.getFieldDefinitions(), wDef.getLabel(layoutMode), wDef.getHelpLabel(layoutMode),
wDef.isTranslated(), wDef.isHandlingLabels(), props, required, subWidgets.toArray(new Widget[0]),
level, wDef.getSelectOptions(), LayoutFunctions.computeWidgetDefinitionId(wDef),
wDef.getRenderingInfos(layoutMode));
widget.setControls(controls);
widget.setTypeCategory(actualWTypeCat);
if (Framework.isDevModeSet()) {
widget.setDefinition(wDef);
}
return widget;
}
@Override
public Layout getLayout(FaceletContext ctx, String layoutName, String mode, String valueName)
throws LayoutException {
return getLayout(ctx, layoutName, mode, valueName, null, false);
}
@Override
public Layout getLayout(FaceletContext ctx, String layoutName, String mode, String valueName,
List<String> selectedRows, boolean selectAllRowsByDefault) {
return getLayout(ctx, layoutName, null, mode, valueName, selectedRows, selectAllRowsByDefault);
}
@Override
public Layout getLayout(FaceletContext ctx, String layoutName, String layoutCategory, String mode,
String valueName, List<String> selectedRows, boolean selectAllRowsByDefault) {
if (StringUtils.isBlank(layoutCategory)) {
layoutCategory = getDefaultStoreCategory();
}
LayoutDefinition layoutDef = getLayoutStore().getLayoutDefinition(layoutCategory, layoutName);
if (layoutDef == null) {
if (log.isDebugEnabled()) {
log.debug("Layout '" + layoutName + "' not found for category '" + layoutCategory + "'");
}
return null;
}
return getLayout(ctx, layoutDef, mode, valueName, selectedRows, selectAllRowsByDefault);
}
@Override
public Layout getLayout(FaceletContext ctx, LayoutDefinition layoutDef, String mode, String valueName,
List<String> selectedRows, boolean selectAllRowsByDefault) {
return getLayout(ctx, null, null, layoutDef, mode, valueName, selectedRows, selectAllRowsByDefault);
}
@Override
public Layout getLayout(FaceletContext ctx, LayoutConversionContext lctx, String conversionCat,
LayoutDefinition layoutDefinition, String mode, String valueName, List<String> selectedRows,
boolean selectAllRowsByDefault) {
if (layoutDefinition == null) {
log.debug("Layout definition is null");
return null;
}
if (ctx == null) {
log.warn("Layout creation computed in a null facelet context: expressions "
+ "found in the layout definition will not be evaluated");
}
LayoutDefinition lDef = layoutDefinition.clone();
if (lctx != null && !StringUtils.isBlank(conversionCat)) {
List<LayoutDefinitionConverter> lcs = getLayoutStore().getLayoutConverters(conversionCat);
for (LayoutDefinitionConverter lc : lcs) {
lDef = lc.getLayoutDefinition(lDef, lctx);
}
}
String layoutName = lDef.getName();
String layoutTypeCategory = lDef.getTypeCategory();
String actualLayoutTypeCategory = getStoreCategory(layoutTypeCategory);
LayoutTypeDefinition layoutTypeDef = null;
String layoutType = lDef.getType();
if (!StringUtils.isBlank(layoutType)) {
// retrieve type for templates and props mapping
layoutTypeDef = getLayoutStore().getLayoutTypeDefinition(actualLayoutTypeCategory, layoutType);
if (layoutTypeDef == null) {
log.warn("Layout type '" + layoutType + "' not found for category '" + layoutTypeCategory + "'");
}
}
String template = lDef.getTemplate(mode);
Map<String, Serializable> props = new HashMap<>();
if (layoutTypeDef != null) {
if (StringUtils.isEmpty(template)) {
template = layoutTypeDef.getTemplate(mode);
}
LayoutTypeConfiguration conf = layoutTypeDef.getConfiguration();
if (conf != null) {
Map<String, Serializable> typeProps = conf.getDefaultPropertyValues(mode);
if (typeProps != null) {
props.putAll(typeProps);
}
}
}
Map<String, Serializable> lprops = lDef.getProperties(mode);
if (lprops != null) {
props.putAll(lprops);
}
LayoutImpl layout;
boolean scaffold = Boolean.parseBoolean(String.valueOf(props.get("scaffold")));
if (scaffold) {
// ignore rows, retrieve all widgets from the definition, and put them in a map held by layout
Map<String, Widget> widgetsMap = new LinkedHashMap<>();
Map<String, WidgetDefinition> widgetDefs = lDef.getWidgetDefinitions();
if (widgetDefs != null) {
for (WidgetDefinition widgetDef : widgetDefs.values()) {
String widgetName = widgetDef.getName();
if (StringUtils.isBlank(widgetName)) {
// no widget at this place
continue;
}
// TODO: handle category for global widgets
String cat = null;
if (StringUtils.isBlank(cat)) {
cat = getDefaultStoreCategory();
}
WidgetDefinition wDef = lookupWidget(lDef, new WidgetReferenceImpl(cat, widgetName));
if (wDef == null) {
log.error("Widget '" + widgetName + "' not found in layout " + layoutName);
continue;
}
Widget widget = getWidget(ctx, lctx, conversionCat, layoutName, lDef, wDef, cat, mode, valueName,
0);
if (widget != null) {
widgetsMap.put(widgetName, widget);
}
}
}
layout = new LayoutImpl(lDef.getName(), mode, template, widgetsMap, props,
LayoutFunctions.computeLayoutDefinitionId(lDef));
} else {
LayoutRowDefinition[] rowsDef = lDef.getRows();
List<LayoutRow> rows = new ArrayList<>();
Set<String> foundRowNames = new HashSet<>();
int rowIndex = -1;
for (LayoutRowDefinition rowDef : rowsDef) {
rowIndex++;
String rowName = rowDef.getName();
if (rowName == null) {
rowName = rowDef.getDefaultName(rowIndex);
if (selectedRows != null && log.isDebugEnabled()) {
log.debug("Generating default name '" + rowName + "' in layout '" + layoutName
+ "' for row or column at index " + rowIndex);
}
}
boolean emptyRow = true;
if (selectedRows != null && !selectedRows.contains(rowName) && !rowDef.isAlwaysSelected()) {
continue;
}
if (selectedRows == null && !selectAllRowsByDefault && !rowDef.isSelectedByDefault()
&& !rowDef.isAlwaysSelected()) {
continue;
}
List<Widget> widgets = new ArrayList<>();
for (WidgetReference widgetRef : rowDef.getWidgetReferences()) {
String widgetName = widgetRef.getName();
if (StringUtils.isBlank(widgetName)) {
// no widget at this place
widgets.add(null);
continue;
}
String cat = widgetRef.getCategory();
if (StringUtils.isBlank(cat)) {
cat = getDefaultStoreCategory();
}
WidgetDefinition wDef = lookupWidget(lDef, new WidgetReferenceImpl(cat, widgetName));
if (wDef == null) {
log.error("Widget '" + widgetName + "' not found in layout " + layoutName);
widgets.add(null);
continue;
}
Widget widget = getWidget(ctx, lctx, conversionCat, layoutName, lDef, wDef, cat, mode, valueName,
0);
if (widget != null) {
emptyRow = false;
}
widgets.add(widget);
}
if (!emptyRow) {
rows.add(new LayoutRowImpl(rowName, rowDef.isSelectedByDefault(), rowDef.isAlwaysSelected(),
widgets, rowDef.getProperties(mode), LayoutFunctions.computeLayoutRowDefinitionId(rowDef)));
}
foundRowNames.add(rowName);
}
if (selectedRows != null) {
Collections.sort(rows, new LayoutRowComparator(selectedRows));
for (String selectedRow : selectedRows) {
if (!foundRowNames.contains(selectedRow)) {
log.warn("Selected row or column named '" + selectedRow + "' " + "was not found in layout '"
+ layoutName + "'");
}
}
}
layout = new LayoutImpl(lDef.getName(), mode, template, rows, lDef.getColumns(), props,
LayoutFunctions.computeLayoutDefinitionId(lDef));
}
layout.setValueName(valueName);
layout.setType(layoutType);
layout.setTypeCategory(actualLayoutTypeCategory);
if (Framework.isDevModeSet()) {
layout.setDefinition(lDef);
// resolve template in "dev" mode, avoiding default lookup on "any"
// mode
Map<String, String> templates = lDef.getTemplates();
String devTemplate = templates != null ? templates.get(BuiltinModes.DEV) : null;
if (layoutTypeDef != null && StringUtils.isEmpty(devTemplate)) {
Map<String, String> typeTemplates = layoutTypeDef.getTemplates();
devTemplate = typeTemplates != null ? typeTemplates.get(BuiltinModes.DEV) : null;
}
layout.setDevTemplate(devTemplate);
}
return layout;
}
@Override
public Widget createWidget(FaceletContext ctx, String type, String mode, String valueName,
List<FieldDefinition> fieldDefinitions, String label, String helpLabel, Boolean translated,
Map<String, Serializable> properties, Widget[] subWidgets) {
return createWidget(
ctx,
createWidgetDefinition(ctx, type, null, mode, valueName, fieldDefinitions, null, label, helpLabel,
translated, properties, subWidgets), mode, valueName, subWidgets);
}
@Override
public Widget createWidget(FaceletContext ctx, WidgetDefinition wDef, String mode, String valueName,
Widget[] subWidgets) {
String wType = wDef.getType();
String wTypeCat = wDef.getTypeCategory();
// fill default property and control values from the widget definition
Map<String, Serializable> props = new HashMap<>();
Map<String, Serializable> controls = new HashMap<>();
String actualWTypeCat = getStoreCategory(wTypeCat);
WidgetTypeDefinition def = getLayoutStore().getWidgetTypeDefinition(actualWTypeCat, wType);
boolean required = false;
WidgetTypeConfiguration conf = def != null ? def.getConfiguration() : null;
if (conf != null) {
Map<String, Serializable> defaultProps = conf.getDefaultPropertyValues(mode);
if (defaultProps != null && !defaultProps.isEmpty()) {
props.putAll(defaultProps);
}
Map<String, Serializable> defaultControls = conf.getDefaultControlValues(mode);
if (defaultControls != null && !defaultControls.isEmpty()) {
controls.putAll(defaultControls);
}
}
Map<String, Serializable> modeProps = wDef.getProperties(mode, mode);
if (modeProps != null) {
props.putAll(modeProps);
Serializable requiredProp = props.get(WidgetDefinition.REQUIRED_PROPERTY_NAME);
if (requiredProp != null) {
if (requiredProp instanceof Boolean) {
required = ((Boolean) requiredProp).booleanValue();
} else if (requiredProp instanceof String) {
required = getBooleanValue(ctx, (String) requiredProp).booleanValue();
} else {
log.error("Invalid property 'required' on widget: '" + requiredProp + "'.");
}
}
}
Map<String, Serializable> modeControls = wDef.getControls(mode, mode);
if (modeControls != null) {
controls.putAll(modeControls);
}
WidgetImpl widget = new WidgetImpl("layout", wDef.getName(), mode, wType, valueName,
wDef.getFieldDefinitions(), wDef.getLabel(mode), wDef.getHelpLabel(mode), wDef.isTranslated(), props,
required, subWidgets, 0, null, LayoutFunctions.computeWidgetDefinitionId(wDef));
widget.setControls(controls);
widget.setTypeCategory(actualWTypeCat);
widget.setDynamic(wDef.isDynamic());
widget.setGlobal(wDef.isGlobal());
if (Framework.isDevModeSet()) {
widget.setDefinition(wDef);
}
return widget;
}
protected WidgetDefinition createWidgetDefinition(FaceletContext ctx, String type, String category, String mode,
String valueName, List<FieldDefinition> fieldDefinitions, String widgetName, String label,
String helpLabel, Boolean translated, Map<String, Serializable> properties, Widget[] subWidgets) {
String wName = widgetName;
if (StringUtils.isBlank(widgetName)) {
wName = type;
}
WidgetDefinitionImpl wDef = new WidgetDefinitionImpl(wName, type, label, helpLabel,
Boolean.TRUE.equals(translated), null, fieldDefinitions, properties, null);
wDef.setDynamic(true);
return wDef;
}
/**
* @since 5.6
*/
protected void registerDisabledPropertyRef(DisabledPropertyRefDescriptor desc) {
disabledPropertyRefsReg.addContribution(desc);
log.info(String.format("Registered disabled property reference descriptor: %s", desc.toString()));
}
/**
* @since 5.6
*/
protected void unregisterDisabledPropertyRef(DisabledPropertyRefDescriptor desc) {
disabledPropertyRefsReg.removeContribution(desc);
log.info(String.format("Removed disabled property reference descriptor: %s", desc.toString()));
}
@Override
public boolean referencePropertyAsExpression(String name, Serializable value, String widgetType,
String widgetTypeCategory, String widgetMode, String template) {
if ((value instanceof String) && (ComponentTagUtils.isValueReference((String) value))) {
return false;
}
String cat = widgetTypeCategory;
if (widgetTypeCategory == null) {
cat = WebLayoutManager.JSF_CATEGORY;
}
for (DisabledPropertyRefDescriptor desc : disabledPropertyRefsReg.getDisabledPropertyRefs()) {
if (Boolean.TRUE.equals(desc.getEnabled()) && desc.matches(name, widgetType, cat, widgetMode, template)) {
return false;
}
}
return true;
}
}