blob: 609c9456a6a759ae667490ec4b3fd83a4d2930ff [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.myfaces.extensions.validator.core.initializer.component;
import org.apache.myfaces.extensions.validator.core.ExtValContext;
import org.apache.myfaces.extensions.validator.core.ExtValCoreConfiguration;
import org.apache.myfaces.extensions.validator.internal.UsageInformation;
import org.apache.myfaces.extensions.validator.internal.UsageCategory;
import org.apache.myfaces.extensions.validator.internal.ToDo;
import org.apache.myfaces.extensions.validator.internal.Priority;
import org.apache.myfaces.extensions.validator.util.ExtValUtils;
import org.apache.myfaces.extensions.validator.util.ReflectionUtils;
import org.apache.myfaces.extensions.validator.core.metadata.CommonMetaDataKeys;
import javax.faces.context.FacesContext;
import javax.faces.component.UIComponent;
import javax.faces.component.html.HtmlInputText;
import javax.faces.component.html.HtmlInputSecret;
import javax.faces.component.html.HtmlSelectBooleanCheckbox;
import javax.faces.component.html.HtmlSelectOneListbox;
import javax.faces.component.html.HtmlSelectOneMenu;
import javax.faces.component.html.HtmlSelectOneRadio;
import javax.faces.component.html.HtmlSelectManyCheckbox;
import javax.faces.component.html.HtmlSelectManyListbox;
import javax.faces.component.html.HtmlSelectManyMenu;
import javax.faces.component.html.HtmlInputTextarea;
import java.util.Map;
/**
* Basic implementation of a {@link ComponentInitializer} which allows an easier handling of required validations and
* provides a default implementation for standard components.
*
* @author Gerhard Petracek
* @since x.x.3
*/
@UsageInformation(UsageCategory.REUSE)
public abstract class AbstractHtmlCoreComponentsComponentInitializer implements ComponentInitializer
{
//short because it influences the state
protected static final String INITIAL_MARKUP_META_DATA_KEY = "OAM_EV_MARKUP_METADATA";
protected Boolean forceComponentInitialization;
/**
* If the component is one of the standard input components, the max length attribute is configured and the
* required attribute is configured (if empty field validation and required initialization is activated)
*
* @param facesContext The JSF Context
* @param uiComponent The component which should be initialised
* @param metaData map which contains the transformed meta-data
*/
public void configureComponent(FacesContext facesContext, UIComponent uiComponent, Map<String, Object> metaData)
{
if(processComponent(uiComponent))
{
if(validateEmptyFields() && isRequiredInitializationActive())
{
configureRequiredAttribute(facesContext, uiComponent, metaData);
}
configureMaxLengthAttribute(facesContext, uiComponent, metaData);
}
}
/**
* Uses the config introduced by JSF 2 for specifying if
* fields without content should be available for required validation.
*
* @return true if fields with empty values should be validated, false otherwise.
*/
protected boolean validateEmptyFields()
{
return ExtValUtils.validateEmptyFields();
}
/**
* Uses the config introduced by prev. ExtVal versions for specifying if
* required initialization should be used
* (it's useful e.g. for client-side validations provided by libs like trinidad).
*
* @return true if ExtVal should transfer meta-data for required fields to the component
*/
protected boolean isRequiredInitializationActive()
{
return ExtValUtils.isRequiredInitializationActive();
}
/**
* The concrete implementation has to initialize the component based on the given meta-data map.
* This method is only called if all pre-conditions are fulfilled.
*
* @param facesContext The JSF Context
* @param uiComponent The UIComponent which should be configured.
* @param metaData map which contains the transformed meta-data
*/
protected abstract void configureRequiredAttribute(FacesContext facesContext,
UIComponent uiComponent,
Map<String, Object> metaData);
/**
* Activates the implementation for special components (-> other components will be ignored).
*
* @param uiComponent The UIComponent which should be configured.
* @return Should the component be initialized.
*/
protected boolean processComponent(UIComponent uiComponent)
{
return uiComponent instanceof HtmlInputText ||
uiComponent instanceof HtmlInputSecret ||
uiComponent instanceof HtmlSelectBooleanCheckbox ||
uiComponent instanceof HtmlSelectOneListbox ||
uiComponent instanceof HtmlSelectOneMenu ||
uiComponent instanceof HtmlSelectOneRadio ||
uiComponent instanceof HtmlSelectManyCheckbox ||
uiComponent instanceof HtmlSelectManyListbox ||
uiComponent instanceof HtmlSelectManyMenu ||
uiComponent instanceof HtmlInputTextarea;
}
/**
* if there is no special attribute at the component which should overrule
* the annotated property return true!
*
* @param uiComponent component which implements the EditableValueHolder interface
* @return false to overrule the annotated property e.g. if component is readonly
*/
@ToDo(value = Priority.MEDIUM, description = "refactor")
protected boolean isRequiredInitializationSupported(UIComponent uiComponent)
{
boolean isReadOnly = !Boolean.FALSE.equals(ReflectionUtils.tryToInvokeMethod(
uiComponent, ReflectionUtils.tryToGetMethod(uiComponent.getClass(), "isReadonly")));
boolean isDisabled = !Boolean.FALSE.equals(ReflectionUtils.tryToInvokeMethod(
uiComponent, ReflectionUtils.tryToGetMethod(uiComponent.getClass(), "isDisabled")));
return !(isReadOnly || isDisabled);
}
/**
* This default implementation uses the transformed meta-data stored via the ({@link CommonMetaDataKeys#MAX_LENGTH}
* key for initializing e.g. the maxLength attribute of the current component
* (of type {@link HtmlInputText} or {@link HtmlInputSecret}.
*
* @param facesContext The JSF Context
* @param uiComponent The component to configure.
* @param metaData map which contains the transformed meta-data
*/
protected void configureMaxLengthAttribute(FacesContext facesContext,
UIComponent uiComponent,
Map<String, Object> metaData)
{
if(metaData.containsKey(CommonMetaDataKeys.MAX_LENGTH))
{
Object maxLength = metaData.get(CommonMetaDataKeys.MAX_LENGTH);
if(!(maxLength instanceof Integer))
{
return;
}
init(); //lazy init
if(uiComponent instanceof HtmlInputText)
{
HtmlInputText htmlInputText = (HtmlInputText)uiComponent;
if (this.forceComponentInitialization)
{
htmlInputText.setMaxlength((Integer) maxLength);
}
else
{
Integer initialMaxLength = (Integer)
htmlInputText.getAttributes().get(INITIAL_MARKUP_META_DATA_KEY);
if (initialMaxLength == null)
{
initialMaxLength = htmlInputText.getMaxlength(); //value overriden by the component
htmlInputText.getAttributes().put(INITIAL_MARKUP_META_DATA_KEY, initialMaxLength);
}
// only override maxlength if not already set by xhtml definition
if (initialMaxLength <= 0)
{
htmlInputText.setMaxlength((Integer) maxLength);
}
}
}
else if(uiComponent instanceof HtmlInputSecret)
{
HtmlInputSecret htmlInputSecret = (HtmlInputSecret)uiComponent;
if (this.forceComponentInitialization)
{
htmlInputSecret.setMaxlength((Integer)maxLength);
}
else
{
Integer initialMaxLength = (Integer)
htmlInputSecret.getAttributes().get(INITIAL_MARKUP_META_DATA_KEY);
if (initialMaxLength == null)
{
initialMaxLength = htmlInputSecret.getMaxlength(); //value overriden by the component
htmlInputSecret.getAttributes().put(INITIAL_MARKUP_META_DATA_KEY, initialMaxLength);
}
// only override maxlength if not already set by xhtml definition
if (initialMaxLength <= 0)
{
htmlInputSecret.setMaxlength((Integer) maxLength);
}
}
}
}
}
protected void init()
{
if (this.forceComponentInitialization == null)
{
this.forceComponentInitialization = !ExtValContext.getContext()
.getModuleConfiguration(ExtValCoreConfiguration.class).activateMarkupMetaData();
}
}
}