/* * (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; } }