[seam-commits] Seam SVN: r12896 - in modules/faces/trunk: api/src/main/java/org/jboss/seam/faces and 3 other directories.
seam-commits at lists.jboss.org
seam-commits at lists.jboss.org
Fri May 28 19:06:52 EDT 2010
Author: dan.j.allen
Date: 2010-05-28 19:06:51 -0400 (Fri, 28 May 2010)
New Revision: 12896
Added:
modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/
modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/ClientId.java
modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/MethodBindingMethodExpressionAdapter.java
modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIInputContainer.java
modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIValidateForm.java
modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIViewAction.java
modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/ValueExpressionAnalyzer.java
modules/faces/trunk/api/src/main/resources/META-INF/faces-config.xml
Removed:
modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/MethodBindingMethodExpressionAdapter.java
modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/UIValidateForm.java
modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/UIViewAction.java
Modified:
modules/faces/trunk/pom.xml
Log:
SEAMFACES-22
also, move components to api
Added: modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/ClientId.java
===================================================================
--- modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/ClientId.java (rev 0)
+++ modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/ClientId.java 2010-05-28 23:06:51 UTC (rev 12896)
@@ -0,0 +1,21 @@
+package org.jboss.seam.faces.component;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.enterprise.util.Nonbinding;
+import javax.inject.Qualifier;
+
+/**
+ * @author Dan Allen
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
+ at Qualifier
+public @interface ClientId {
+ /**
+ * The search expression that matches one or more UIComponent instances by its clientId.
+ */
+ @Nonbinding String value() default "";
+}
Copied: modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/MethodBindingMethodExpressionAdapter.java (from rev 12895, modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/MethodBindingMethodExpressionAdapter.java)
===================================================================
--- modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/MethodBindingMethodExpressionAdapter.java (rev 0)
+++ modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/MethodBindingMethodExpressionAdapter.java 2010-05-28 23:06:51 UTC (rev 12896)
@@ -0,0 +1,339 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.faces.component;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.ExpressionFactory;
+import javax.el.MethodExpression;
+import javax.el.MethodInfo;
+import javax.el.ValueExpression;
+import javax.faces.component.StateHolder;
+import javax.faces.context.FacesContext;
+import javax.faces.el.EvaluationException;
+import javax.faces.el.MethodBinding;
+import javax.faces.el.MethodNotFoundException;
+
+/**
+ * <p>
+ * Wrap a MethodExpression instance and expose it as a MethodBinding
+ * </p>
+ *
+ */
+class MethodBindingMethodExpressionAdapter extends MethodBinding implements StateHolder, Serializable
+{
+
+ private static final long serialVersionUID = 7334926223014401689L;
+ private MethodExpression methodExpression = null;
+ private boolean tranzient;
+
+ public MethodBindingMethodExpressionAdapter()
+ {
+ } // for StateHolder
+
+ MethodBindingMethodExpressionAdapter(final MethodExpression methodExpression)
+ {
+ this.methodExpression = methodExpression;
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public Object invoke(final FacesContext context, final Object params[]) throws EvaluationException, MethodNotFoundException
+ {
+ assert (null != methodExpression);
+ if (context == null)
+ {
+ throw new NullPointerException("FacesConext -> null");
+ }
+
+ Object result = null;
+ try
+ {
+ result = methodExpression.invoke(context.getELContext(), params);
+ }
+ catch (javax.el.MethodNotFoundException e)
+ {
+ throw new javax.faces.el.MethodNotFoundException(e);
+ }
+ catch (javax.el.PropertyNotFoundException e)
+ {
+ throw new EvaluationException(e);
+ }
+ catch (ELException e)
+ {
+ Throwable cause = e.getCause();
+ if (cause == null)
+ {
+ cause = e;
+ }
+ throw new EvaluationException(cause);
+ }
+ catch (NullPointerException e)
+ {
+ throw new MethodNotFoundException(e);
+ }
+ return result;
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public Class<?> getType(final FacesContext context) throws MethodNotFoundException
+ {
+ assert (null != methodExpression);
+ if (context == null)
+ {
+ throw new NullPointerException("FacesConext -> null");
+ }
+ Class<?> result = null;
+ if (context == null)
+ {
+ throw new NullPointerException();
+ }
+
+ try
+ {
+ MethodInfo mi = methodExpression.getMethodInfo(context.getELContext());
+ result = mi.getReturnType();
+ }
+ catch (javax.el.PropertyNotFoundException e)
+ {
+ throw new MethodNotFoundException(e);
+ }
+ catch (javax.el.MethodNotFoundException e)
+ {
+ throw new MethodNotFoundException(e);
+ }
+ catch (ELException e)
+ {
+ throw new MethodNotFoundException(e);
+ }
+ return result;
+ }
+
+ @Override
+ public String getExpressionString()
+ {
+ assert (null != methodExpression);
+ return methodExpression.getExpressionString();
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public boolean equals(final Object other)
+ {
+ if (this == other)
+ {
+ return true;
+ }
+ if (other instanceof MethodBindingMethodExpressionAdapter)
+ {
+ return methodExpression.equals(((MethodBindingMethodExpressionAdapter) other).getWrapped());
+ }
+ else if (other instanceof MethodBinding)
+ {
+ MethodBinding binding = (MethodBinding) other;
+
+ // We'll need to do a little leg work to determine
+ // if the MethodBinding is equivalent to the
+ // wrapped MethodExpression
+ String expr = binding.getExpressionString();
+ int idx = expr.indexOf('.');
+ String target = expr.substring(0, idx).substring(2);
+ String t = expr.substring(idx + 1);
+ String method = t.substring(0, (t.length() - 1));
+
+ FacesContext context = FacesContext.getCurrentInstance();
+ ELContext elContext = context.getELContext();
+ MethodInfo controlInfo = methodExpression.getMethodInfo(elContext);
+
+ // ensure the method names are the same
+ if (!controlInfo.getName().equals(method))
+ {
+ return false;
+ }
+
+ // Using the target, create an expression and evaluate
+ // it.
+ ExpressionFactory factory = context.getApplication().getExpressionFactory();
+ ValueExpression ve = factory.createValueExpression(elContext, "#{" + target + '}', Object.class);
+ if (ve == null)
+ {
+ return false;
+ }
+
+ Object result = ve.getValue(elContext);
+
+ if (result == null)
+ {
+ return false;
+ }
+
+ // Get all of the methods with the matching name and try
+ // to find a match based on controlInfo's return and parameter
+ // types
+ Class<?> type = binding.getType(context);
+ Method[] methods = result.getClass().getMethods();
+ for (Method meth : methods)
+ {
+ if (meth.getName().equals(method) && type.equals(controlInfo.getReturnType()) && Arrays.equals(meth.getParameterTypes(), controlInfo.getParamTypes()))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+
+ }
+
+ @Override
+ public int hashCode()
+ {
+ assert (null != methodExpression);
+
+ return methodExpression.hashCode();
+ }
+
+ public boolean isTransient()
+ {
+ return this.tranzient;
+ }
+
+ public void setTransient(final boolean tranzient)
+ {
+ this.tranzient = tranzient;
+ }
+
+ public Object saveState(final FacesContext context)
+ {
+ if (context == null)
+ {
+ throw new NullPointerException();
+ }
+ Object result = null;
+ if (!tranzient)
+ {
+ if (methodExpression instanceof StateHolder)
+ {
+ Object[] stateStruct = new Object[2];
+
+ // save the actual state of our wrapped methodExpression
+ stateStruct[0] = ((StateHolder) methodExpression).saveState(context);
+ // save the class name of the methodExpression impl
+ stateStruct[1] = methodExpression.getClass().getName();
+
+ result = stateStruct;
+ }
+ else
+ {
+ result = methodExpression;
+ }
+ }
+
+ return result;
+
+ }
+
+ public void restoreState(final FacesContext context, final Object state)
+ {
+ if (context == null)
+ {
+ throw new NullPointerException();
+ }
+ // if we have state
+ if (null == state)
+ {
+ return;
+ }
+
+ if (!(state instanceof MethodExpression))
+ {
+ Object[] stateStruct = (Object[]) state;
+ Object savedState = stateStruct[0];
+ String className = stateStruct[1].toString();
+ MethodExpression result = null;
+
+ Class<?> toRestoreClass = null;
+ if (null != className)
+ {
+ try
+ {
+ toRestoreClass = loadClass(className, this);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new IllegalStateException(e.getMessage());
+ }
+
+ if (null != toRestoreClass)
+ {
+ try
+ {
+ result = (MethodExpression) toRestoreClass.newInstance();
+ }
+ catch (InstantiationException e)
+ {
+ throw new IllegalStateException(e.getMessage());
+ }
+ catch (IllegalAccessException a)
+ {
+ throw new IllegalStateException(a.getMessage());
+ }
+ }
+
+ if ((null != result) && (null != savedState))
+ {
+ // don't need to check transient, since that was
+ // done on the saving side.
+ ((StateHolder) result).restoreState(context, savedState);
+ }
+ methodExpression = result;
+ }
+ }
+ else
+ {
+ methodExpression = (MethodExpression) state;
+ }
+ }
+
+ public MethodExpression getWrapped()
+ {
+ return methodExpression;
+ }
+
+ //
+ // Helper methods for StateHolder
+ //
+ private static Class<?> loadClass(final String name, final Object fallbackClass) throws ClassNotFoundException
+ {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ if (loader == null)
+ {
+ loader = fallbackClass.getClass().getClassLoader();
+ }
+ return Class.forName(name, true, loader);
+ }
+}
\ No newline at end of file
Added: modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIInputContainer.java
===================================================================
--- modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIInputContainer.java (rev 0)
+++ modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIInputContainer.java 2010-05-28 23:06:51 UTC (rev 12896)
@@ -0,0 +1,520 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.faces.component;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.el.ValueReference;
+import javax.faces.FacesException;
+import javax.faces.application.FacesMessage;
+import javax.faces.component.EditableValueHolder;
+import javax.faces.component.FacesComponent;
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIComponentBase;
+import javax.faces.component.UIMessage;
+import javax.faces.component.UINamingContainer;
+import javax.faces.component.UIViewRoot;
+import javax.faces.component.html.HtmlOutputLabel;
+import javax.faces.context.FacesContext;
+import javax.faces.validator.BeanValidator;
+import javax.validation.Validation;
+import javax.validation.ValidationException;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+
+/**
+ * <strong>UIInputContainer</strong> is a supplamental component for a JSF 2.0 composite component
+ * encapsulating one or more input components (<strong>EditableValueHolder</strong>),
+ * their corresponding message components (<strong>UIMessage</strong>) and
+ * a label (<strong>HtmlOutputLabel</strong>). This component takes care of wiring the
+ * label to the first input and the messages to each input in sequence. It also
+ * assigns two implicit attribute values, "required" and "invalid" to indicate that
+ * a required input field is present and whether there are any validation errors, respectively.
+ * To determine if a input field is required, both the required attribute is consulted and
+ * whether the property has Bean Validation constraints.
+ * Finally, if the "label" attribute is not provided on the composite component, the
+ * label value will be derived from the id of the composite component, for convenience.
+ *
+ * <p>Composite component definition example (minus layout):</p>
+ * <pre>
+ * <cc:interface componentType="org.jboss.seam.faces.InputContainer"/>
+ * <cc:implementation>
+ * <h:outputLabel id="label" value="#{cc.attrs.label}:" styleClass="#{cc.attrs.invalid ? 'invalid' : ''}">
+ * <h:ouputText styleClass="required" rendered="#{cc.attrs.required}" value="*"/>
+ * </h:outputLabel>
+ * <cc:insertChildren/>
+ * <h:message id="message" errorClass="invalid message" rendered="#{cc.attrs.invalid}"/>
+ * </cc:implementation>
+ * </pre>
+ *
+ * <p>Composite component usage example:</p>
+ * <pre>
+ * <example:inputContainer id="name">
+ * <h:inputText id="input" value="#{person.name}"/>
+ * </example:inputContainer>
+ * </pre>
+ *
+ * <p>Possible enhancements:</p>
+ * <ul>
+ * <li>append styleClass "invalid" to label, inputs and messages when invalid</li>
+ * </ul>
+ *
+ * @author Dan Allen
+ */
+ at FacesComponent(UIInputContainer.COMPONENT_TYPE)
+public class UIInputContainer extends UIComponentBase implements NamingContainer
+{
+ /**
+ * The standard component type for this component.
+ */
+ public static final String COMPONENT_TYPE = "org.jboss.seam.faces.InputContainer";
+
+ protected static final String HTML_ID_ATTR_NAME = "id";
+ protected static final String HTML_CLASS_ATTR_NAME = "class";
+ protected static final String HTML_STYLE_ATTR_NAME = "style";
+
+ private boolean beanValidationPresent = false;
+
+ public UIInputContainer()
+ {
+ beanValidationPresent = isClassPresent("javax.validation.Validator");
+ }
+
+ public String getFamily()
+ {
+ return UINamingContainer.COMPONENT_FAMILY;
+ }
+
+ /**
+ * The name of the auto-generated composite component attribute
+ * that holds a boolean indicating whether the the template contains
+ * an invalid input.
+ */
+ public String getInvalidAttributeName()
+ {
+ return "invalid";
+ }
+
+ /**
+ * The name of the auto-generated composite component attribute
+ * that holds a boolean indicating whether the template contains
+ * a required input.
+ */
+ public String getRequiredAttributeName()
+ {
+ return "required";
+ }
+
+ /**
+ * The name of the composite component attribute that
+ * holds the string label for this set of inputs. If the
+ * label attribute is not provided, one will be generated
+ * from the id of the composite component or, if the id is
+ * defaulted, the name of the property bound to the first input.
+ */
+ public String getLabelAttributeName()
+ {
+ return "label";
+ }
+
+ /**
+ * The name of the auto-generated composite component attribute
+ * that holds the elements in this input container. The
+ * elements include the label, a list of inputs and a cooresponding
+ * list of messages.
+ */
+ public String getElementsAttributeName()
+ {
+ return "elements";
+ }
+
+ /**
+ * The name of the composite component attribute that holds a boolean
+ * indicating whether the component template should be enclosed in
+ * an HTML element, so that it be referenced from JavaScript.
+ */
+ public String getEncloseAttributeName()
+ {
+ return "enclose";
+ }
+
+ public String getContainerElementName()
+ {
+ return "div";
+ }
+
+ public String getDefaultLabelId()
+ {
+ return "label";
+ }
+
+ public String getDefaultInputId()
+ {
+ return "input";
+ }
+
+ public String getDefaultMessageId()
+ {
+ return "message";
+ }
+
+ @Override
+ public void encodeBegin(FacesContext context) throws IOException
+ {
+ if (!isRendered())
+ {
+ return;
+ }
+
+ super.encodeBegin(context);
+
+ InputContainerElements elements = scan(getFacet(UIComponent.COMPOSITE_FACET_NAME), null, context);
+ //assignIds(elements, context);
+ wire(elements, context);
+
+ getAttributes().put(getElementsAttributeName(), elements);
+
+ if (elements.hasValidationError())
+ {
+ getAttributes().put(getInvalidAttributeName(), true);
+ }
+
+ // set the required attribute, but only if the user didn't already assign it
+ if (!getAttributes().containsKey(getRequiredAttributeName()) && elements.hasRequiredInput())
+ {
+ getAttributes().put(getRequiredAttributeName(), true);
+ }
+
+ if (!getAttributes().containsKey(getLabelAttributeName()))
+ {
+ getAttributes().put(getLabelAttributeName(), generateLabel(elements, context));
+ }
+
+ if (Boolean.TRUE.equals(getAttributes().get(getEncloseAttributeName())))
+ {
+ startContainerElement(context);
+ }
+ }
+
+ @Override
+ public void encodeEnd(FacesContext context) throws IOException
+ {
+ if (!isRendered())
+ {
+ return;
+ }
+
+ super.encodeEnd(context);
+
+ if (Boolean.TRUE.equals(getAttributes().get(getEncloseAttributeName())))
+ {
+ endContainerElement(context);
+ }
+ }
+
+ protected void startContainerElement(FacesContext context) throws IOException
+ {
+ context.getResponseWriter().startElement(getContainerElementName(), this);
+ String style = (getAttributes().get("style") != null ? getAttributes().get("style").toString().trim() : null);
+ if (style.length() > 0)
+ {
+ context.getResponseWriter().writeAttribute(HTML_STYLE_ATTR_NAME, style, HTML_STYLE_ATTR_NAME);
+ }
+ String styleClass = (getAttributes().get("styleClass") != null ? getAttributes().get("styleClass").toString().trim() : null);
+ if (styleClass.length() > 0)
+ {
+ context.getResponseWriter().writeAttribute(HTML_CLASS_ATTR_NAME, styleClass, HTML_CLASS_ATTR_NAME);
+ }
+ context.getResponseWriter().writeAttribute(HTML_ID_ATTR_NAME, getClientId(context), HTML_ID_ATTR_NAME);
+ }
+
+ protected void endContainerElement(FacesContext context) throws IOException
+ {
+ context.getResponseWriter().endElement(getContainerElementName());
+ }
+
+ protected String generateLabel(InputContainerElements elements, FacesContext context)
+ {
+ String name = getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX) ? elements.getPropertyName(context) : getId();
+ return name.substring(0, 1).toUpperCase() + name.substring(1);
+ }
+
+ /**
+ * Walk the component tree branch built by the composite component and locate
+ * the input container elements.
+ *
+ * @return a composite object of the input container elements
+ */
+ protected InputContainerElements scan(UIComponent component, InputContainerElements elements, FacesContext context)
+ {
+ if (elements == null) {
+ elements = new InputContainerElements();
+ }
+
+ // NOTE we need to walk the tree ignoring rendered attribute because it's condition
+ // could be based on what we discover
+ if (elements.getLabel() == null && component instanceof HtmlOutputLabel)
+ {
+ elements.setLabel((HtmlOutputLabel) component);
+ }
+ else if (component instanceof EditableValueHolder)
+ {
+ elements.registerInput((EditableValueHolder) component, getDefaultValidator(context), context);
+ }
+ else if (component instanceof UIMessage)
+ {
+ elements.registerMessage((UIMessage) component);
+ }
+ // may need to walk smarter to ensure "element of least suprise"
+ for (UIComponent child : component.getChildren())
+ {
+ scan(child, elements, context);
+ }
+
+ return elements;
+ }
+
+ // assigning ids seems to break form submissions, but I don't know why
+ public void assignIds(InputContainerElements elements, FacesContext context)
+ {
+ boolean refreshIds = false;
+ if (getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
+ {
+ setId(elements.getPropertyName(context));
+ refreshIds = true;
+ }
+ UIComponent label = elements.getLabel();
+ if (label != null)
+ {
+ if (label.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
+ {
+ label.setId(getDefaultLabelId());
+ }
+ else if (refreshIds) {
+ label.setId(label.getId());
+ }
+ }
+ for (int i = 0, len = elements.getInputs().size(); i < len; i++)
+ {
+ UIComponent input = (UIComponent) elements.getInputs().get(i);
+ if (input.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
+ {
+ input.setId(getDefaultInputId() + (i == 0 ? "" : (i + 1)));
+ }
+ else if (refreshIds) {
+ input.setId(input.getId());
+ }
+ }
+ for (int i = 0, len = elements.getMessages().size(); i < len; i++)
+ {
+ UIComponent msg = elements.getMessages().get(i);
+ if (msg.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
+ {
+ msg.setId(getDefaultMessageId() + (i == 0 ? "" : (i + 1)));
+ }
+ else if (refreshIds) {
+ msg.setId(msg.getId());
+ }
+ }
+ }
+
+ /**
+ * Wire the label and messages to the input(s)
+ */
+ protected void wire(InputContainerElements elements, FacesContext context)
+ {
+ elements.wire(context);
+ }
+
+ /**
+ * Get the default Bean Validation Validator to read the contraints for a property.
+ */
+ private Validator getDefaultValidator(FacesContext context) throws FacesException
+ {
+ if (!beanValidationPresent) {
+ return null;
+ }
+
+ ValidatorFactory validatorFactory;
+ Object cachedObject = context.getExternalContext().getApplicationMap().get(BeanValidator.VALIDATOR_FACTORY_KEY);
+ if (cachedObject instanceof ValidatorFactory)
+ {
+ validatorFactory = (ValidatorFactory) cachedObject;
+ }
+ else
+ {
+ try
+ {
+ validatorFactory = Validation.buildDefaultValidatorFactory();
+ }
+ catch (ValidationException e)
+ {
+ throw new FacesException("Could not build a default Bean Validator factory", e);
+ }
+ context.getExternalContext().getApplicationMap().put(BeanValidator.VALIDATOR_FACTORY_KEY, validatorFactory);
+ }
+ return validatorFactory.getValidator();
+ }
+
+ private boolean isClassPresent(String fqcn)
+ {
+ try
+ {
+ if (Thread.currentThread().getContextClassLoader() != null)
+ {
+ return Thread.currentThread().getContextClassLoader().loadClass(fqcn) != null;
+ }
+ else
+ {
+ return Class.forName(fqcn) != null;
+ }
+ }
+ catch (ClassNotFoundException e)
+ {
+ return false;
+ }
+ catch (NoClassDefFoundError e)
+ {
+ return false;
+ }
+ }
+
+ public static class InputContainerElements
+ {
+ private String propertyName;
+ private HtmlOutputLabel label;
+ private List<EditableValueHolder> inputs = new ArrayList<EditableValueHolder>();
+ private List<UIMessage> messages = new ArrayList<UIMessage>();
+ private boolean validationError = false;
+ private boolean requiredInput = false;
+
+ public HtmlOutputLabel getLabel()
+ {
+ return label;
+ }
+
+ public void setLabel(HtmlOutputLabel label)
+ {
+ this.label = label;
+ }
+
+ public List<EditableValueHolder> getInputs()
+ {
+ return inputs;
+ }
+
+ public void registerInput(EditableValueHolder input, Validator validator, FacesContext context)
+ {
+ inputs.add(input);
+ if (input.isRequired() || isRequiredByConstraint(input, validator, context))
+ {
+ requiredInput = true;
+ }
+ if (!input.isValid())
+ {
+ validationError = true;
+ }
+ // optimization to avoid loop if already flagged
+ else if (!validationError)
+ {
+ Iterator<FacesMessage> it = context.getMessages(((UIComponent) input).getClientId(context));
+ while (it.hasNext())
+ {
+ if (it.next().getSeverity().compareTo(FacesMessage.SEVERITY_WARN) >= 0)
+ {
+ validationError = true;
+ break;
+ }
+ }
+ }
+ }
+
+ public List<UIMessage> getMessages()
+ {
+ return messages;
+ }
+
+ public void registerMessage(UIMessage message)
+ {
+ messages.add(message);
+ }
+
+ public boolean hasValidationError()
+ {
+ return validationError;
+ }
+
+ public boolean hasRequiredInput()
+ {
+ return requiredInput;
+ }
+
+ private boolean isRequiredByConstraint(EditableValueHolder input, Validator validator, FacesContext context)
+ {
+ if (validator == null) {
+ return false;
+ }
+
+ // NOTE believe it or not, getValueReference on ValueExpression is broken, so we have to do it ourselves
+ ValueReference vref = new ValueExpressionAnalyzer(((UIComponent) input).getValueExpression("value"))
+ .getValueReference(context.getELContext());
+ return validator.getConstraintsForClass(vref.getBase().getClass())
+ .getConstraintsForProperty((String) vref.getProperty()).hasConstraints();
+ }
+
+ public String getPropertyName(FacesContext context) {
+ if (propertyName != null) {
+ return propertyName;
+ }
+
+ if (inputs.size() == 0) {
+ return null;
+ }
+
+ propertyName = (String) new ValueExpressionAnalyzer(((UIComponent) inputs.get(0)).getValueExpression("value"))
+ .getValueReference(context.getELContext()).getProperty();
+ return propertyName;
+ }
+
+ public void wire(FacesContext context)
+ {
+ int numInputs = inputs.size();
+ if (numInputs > 0)
+ {
+ if (label != null)
+ {
+ label.setFor(((UIComponent) inputs.get(0)).getClientId(context));
+ }
+ for (int i = 0, len = messages.size(); i < len; i++)
+ {
+ if (i < numInputs)
+ {
+ messages.get(i).setFor(((UIComponent) inputs.get(i)).getClientId(context));
+ }
+ }
+ }
+ }
+ }
+}
Copied: modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIValidateForm.java (from rev 12895, modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/UIValidateForm.java)
===================================================================
--- modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIValidateForm.java (rev 0)
+++ modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIValidateForm.java 2010-05-28 23:06:51 UTC (rev 12896)
@@ -0,0 +1,183 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.seam.faces.component;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.util.AnnotationLiteral;
+import javax.faces.component.FacesComponent;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIForm;
+import javax.faces.component.UIInput;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PostValidateEvent;
+import javax.faces.event.PreValidateEvent;
+import javax.faces.validator.Validator;
+import javax.faces.validator.ValidatorException;
+
+import org.jboss.seam.faces.event.qualifier.After;
+import org.jboss.seam.faces.event.qualifier.Before;
+import org.jboss.weld.extensions.beanManager.BeanManagerAccessor;
+
+/**
+ * @author <a href="mailto:lincolnbaxter at gmail.com>Lincoln Baxter, III</a>
+ *
+ */
+ at FacesComponent(UIValidateForm.COMPONENT_TYPE)
+public class UIValidateForm extends UIInput
+{
+ private static final AnnotationLiteral<Before> BEFORE = new AnnotationLiteral<Before>()
+ {
+ private static final long serialVersionUID = 7631699535063526392L;
+ };
+ private static final AnnotationLiteral<After> AFTER = new AnnotationLiteral<After>()
+ {
+ private static final long serialVersionUID = -929128236303355107L;
+ };
+
+ public static final String COMPONENT_TYPE = "org.jboss.seam.faces.ValidateForm";
+ public static final String COMPONENT_FAMILY = "org.jboss.seam.faces.ValidateForm";
+
+ private String validatorId = "";
+ private String fields = "";
+ private Map<String, UIInput> components = new HashMap<String, UIInput>();
+
+ @Override
+ public String getFamily()
+ {
+ return COMPONENT_FAMILY;
+ }
+
+ @Override
+ public void validate(final FacesContext context)
+ {
+ context.getApplication().publishEvent(context, PreValidateEvent.class, UIValidateForm.class, this);
+ BeanManager manager = BeanManagerAccessor.getManager();
+ manager.fireEvent(this, BEFORE);
+
+ Validator validator = context.getApplication().createValidator(validatorId);
+ if (validator == null)
+ {
+ throw new IllegalArgumentException("Could not create Validator with id: [" + validatorId + "]");
+ }
+
+ try
+ {
+ UIComponent parent = this.getParent();
+ validator.validate(context, parent, components);
+ }
+ catch (ValidatorException e)
+ {
+ setValid(false);
+ for (UIInput comp : components.values())
+ {
+ comp.setValid(false);
+ // TODO Put this back when attributes can control it
+ // context.addMessage(comp.getClientId(), e.getFacesMessage());
+ }
+ context.addMessage(null, e.getFacesMessage());
+ }
+
+ manager.fireEvent(this, AFTER);
+ context.getApplication().publishEvent(context, PostValidateEvent.class, UIValidateForm.class, this);
+ }
+
+ /**
+ * Attempt to locate the form in which this component resides. If the
+ * component is not within a UIForm tag, throw an exception.
+ */
+ public UIForm locateForm()
+ {
+ UIComponent parent = this.getParent();
+ while (!(parent instanceof UIForm))
+ {
+ if ((parent == null) || (parent instanceof UIViewRoot))
+ {
+ throw new IllegalStateException("The UIValidateForm (<s:validateForm />) component must be placed within a UIForm (<h:form>)");
+ }
+ parent = parent.getParent();
+ }
+ return (UIForm) parent;
+ }
+
+ /*
+ * Prevent any rendered output.
+ */
+
+ @Override
+ public void encodeAll(final FacesContext context) throws IOException
+ {
+ locateForm();
+ }
+
+ @Override
+ public void encodeBegin(final FacesContext context) throws IOException
+ {
+ }
+
+ @Override
+ public void encodeEnd(final FacesContext context) throws IOException
+ {
+ }
+
+ @Override
+ public void encodeChildren(final FacesContext context) throws IOException
+ {
+ }
+
+ /*
+ * Getters & Setters
+ */
+
+ public String getFields()
+ {
+ return fields;
+ }
+
+ public void setFields(final String fields)
+ {
+ this.fields = fields;
+ }
+
+ public String getValidatorId()
+ {
+ return validatorId;
+ }
+
+ public void setValidatorId(final String validatorId)
+ {
+ this.validatorId = validatorId;
+ }
+
+ /**
+ * @param components
+ */
+ public void setComponents(final Map<String, UIInput> components)
+ {
+ this.components = components;
+ }
+}
Copied: modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIViewAction.java (from rev 12895, modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/UIViewAction.java)
===================================================================
--- modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIViewAction.java (rev 0)
+++ modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/UIViewAction.java 2010-05-28 23:06:51 UTC (rev 12896)
@@ -0,0 +1,677 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.faces.component;
+
+import javax.el.MethodExpression;
+import javax.faces.FacesException;
+import javax.faces.FactoryFinder;
+import javax.faces.application.NavigationHandler;
+import javax.faces.component.ActionSource2;
+import javax.faces.component.FacesComponent;
+import javax.faces.component.UICommand;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIComponentBase;
+import javax.faces.component.UIViewParameter;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.context.FacesContextWrapper;
+import javax.faces.el.MethodBinding;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.ActionEvent;
+import javax.faces.event.ActionListener;
+import javax.faces.event.FacesEvent;
+import javax.faces.event.PhaseId;
+import javax.faces.event.PreRenderViewEvent;
+import javax.faces.lifecycle.Lifecycle;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.view.ViewMetadata;
+import javax.faces.webapp.FacesServlet;
+
+/**
+ * <p>
+ * <strong>UIViewAction</strong> is an {@link ActionSource2} {@link UIComponent}
+ * that specifies an application-specific command (or action)--defined as an EL
+ * method expression--to be invoked during one of the JSF lifecycle phases that
+ * proceeds view rendering. This component must be declared as a child of the
+ * {@link ViewMetadata} facet of the {@link UIViewRoot} so that it gets
+ * incorporated into the JSF lifecycle on both non-faces (initial) requests and
+ * faces (postback) requests.
+ * </p>
+ *
+ * <p>
+ * The purpose of this component is to provide a light-weight front-controller
+ * solution for executing code upon the loading of a JSF view to support the
+ * integration of system services, content retrieval, view management, and
+ * navigation. This functionality is especially useful for non-faces (initial)
+ * requests.
+ * </p>
+ *
+ * <p>
+ * The {@link UIViewAction} component is closely tied to the
+ * {@link UIViewParameter} component. The {@link UIViewParameter} component
+ * binds a request parameter to a model property. Most of the time, this binding
+ * is used to populate the model with data that supports the method being
+ * invoked by a {@link UIViewAction} component, much like form inputs populate
+ * the model with data to support the method being invoked by a
+ * {@link UICommand} component.
+ * </p>
+ *
+ * <p>
+ * When the <literal>decode()</literal> method of the {@link UIViewAction} is
+ * invoked, it will queue an {@link ActionEvent} to be broadcast to all
+ * interested listeners when the <literal>broadcast()</literal> method is
+ * invoked.
+ * </p>
+ *
+ * <p>
+ * If the value of the component's <literal>immediate</literal> attribute is
+ * <literal>true</literal>, the action will be invoked during the Apply Request
+ * Values JSF lifecycle phase. Otherwise, the action will be invoked during the
+ * Invoke Application phase, the default behavior. The phase cannot be set
+ * explicitly in the <literal>phase</literal> attribute, which takes precedence
+ * over the <literal>immediate</literal> attribute.
+ * </p>
+ *
+ * <p>
+ * The invocation of the action is normally suppressed (meaning the
+ * {@link ActionEvent} is not queued) on a faces request. It can be enabled by
+ * setting the component's <literal>onPostback</literal> attribute to
+ * <literal>true</literal>. Execution of the method can be subject to a required
+ * condition for all requests by assigning an EL value expression of expected
+ * type boolean to the component's <literal>if</literal> attribute, which must
+ * evaluate to <literal>true</literal> for the action to be invoked.
+ * </p>
+ *
+ * <p>
+ * The {@link NavigationHandler} is consulted after the action is invoked to
+ * carry out the navigation case that matches the action signature and outcome.
+ * If a navigation case is matched, or the response is marked complete by the
+ * action, subsequent {@link UIViewAction} components associated with the
+ * current view are short-circuited. The lifecycle then advances appropriately.
+ * </p>
+ *
+ * <p>
+ * It's important to note that the full component tree is not built before the
+ * UIViewAction components are processed on an non-faces (initial) request.
+ * Rather, the component tree only contains the {@link ViewMetadata}, an
+ * important part of the optimization of this component and what sets it apart
+ * from a {@link PreRenderViewEvent} listener.
+ * </p>
+ *
+ * @author Dan Allen
+ * @author Andy Schwartz
+ *
+ * @see UIViewParameter
+ */
+ at FacesComponent(
+// tagName = "viewAction",
+// namespace = "http://jboss.org/seam/faces",
+// (see
+// https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=594)
+value = UIViewAction.COMPONENT_TYPE)
+public class UIViewAction extends UIComponentBase implements ActionSource2
+{
+
+ // ------------------------------------------------------ Manifest Constants
+
+ /**
+ * <p>
+ * The standard component type for this component.
+ * </p>
+ */
+ public static final String COMPONENT_TYPE = "org.jboss.seam.faces.ViewAction";
+
+ /**
+ * <p>
+ * The standard component family for this component.
+ * </p>
+ */
+ public static final String COMPONENT_FAMILY = "org.jboss.seam.faces.ViewAction";
+
+ /**
+ * Properties that are tracked by state saving.
+ */
+ enum PropertyKeys
+ {
+
+ onPostback, actionExpression, immediate, phase, ifAttr("if");
+ private String name;
+
+ PropertyKeys()
+ {
+ }
+
+ PropertyKeys(final String name)
+ {
+ this.name = name;
+ }
+
+ @Override
+ public String toString()
+ {
+ return name != null ? name : super.toString();
+ }
+ }
+
+ // ------------------------------------------------------------ Constructors
+ /**
+ * <p>
+ * Create a new {@link UIViewAction} instance with default property values.
+ * </p>
+ */
+ public UIViewAction()
+ {
+ super();
+ setRendererType(null);
+ }
+
+ // -------------------------------------------------------------- Properties
+ @Override
+ public String getFamily()
+ {
+ return COMPONENT_FAMILY;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @deprecated This has been replaced by {@link #getActionExpression}.
+ */
+ @Deprecated
+ public MethodBinding getAction()
+ {
+ MethodBinding result = null;
+ MethodExpression me;
+
+ if (null != (me = getActionExpression()))
+ {
+ result = new MethodBindingMethodExpressionAdapter(me);
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @deprecated This has been replaced by
+ * {@link #setActionExpression(javax.el.MethodExpression)}.
+ * @throws UnsupportedOperationException if called
+ */
+ @Deprecated
+ public void setAction(final MethodBinding action)
+ {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ /**
+ * Action listeners are not supported by the {@link UIViewAction} component.
+ *
+ * @throws UnsupportedOperationException if called
+ */
+ @SuppressWarnings("deprecation")
+ public MethodBinding getActionListener()
+ {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ /**
+ * Action listeners are not supported by the {@link UIViewAction} component.
+ *
+ * @throws UnsupportedOperationException if called
+ */
+ @SuppressWarnings("deprecation")
+ public void setActionListener(final MethodBinding actionListener)
+ {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ /**
+ * Returns the value which dictates the JSF lifecycle phase in which the
+ * action is invoked. If the value of this attribute is
+ * <literal>true</literal>, the action will be invoked in the Apply Request
+ * Values phase. If the value of this attribute is <literal>false</literal>,
+ * the default, the action will be invoked in the Invoke Application Phase.
+ */
+ public boolean isImmediate()
+ {
+ return (Boolean) getStateHelper().eval(PropertyKeys.immediate, false);
+ }
+
+ /**
+ * Sets the immediate flag, which controls the JSF lifecycle in which the
+ * action is invoked.
+ */
+ public void setImmediate(final boolean immediate)
+ {
+ getStateHelper().put(PropertyKeys.immediate, immediate);
+ }
+
+ /**
+ * <p>
+ * Returns the name of the phase in which the action is to be queued. Only
+ * the following phases are supported (case does not matter):
+ * </p>
+ * <ul>
+ * <li>APPLY_REQUEST_VALUES</li>
+ * <li>PROCESS_VALIDATIONS</li>
+ * <li>UPDATE_MODEL_VALUES</li>
+ * <li>INVOKE_APPLICATION</li>
+ * </ul>
+ * <p>
+ * If the phase is set, it takes precedence over the immediate flag.
+ * </p>
+ */
+ public String getPhase()
+ {
+ String phase = (String) getStateHelper().eval(PropertyKeys.phase);
+ if (phase != null)
+ {
+ phase = phase.toUpperCase();
+ }
+ return phase;
+ }
+
+ /**
+ * Set the name of the phase in which the action is to be queued.
+ */
+ public void setPhase(final String phase)
+ {
+ getStateHelper().put(PropertyKeys.phase, phase);
+ }
+
+ public PhaseId getPhaseId()
+ {
+ String phase = getPhase();
+ if (phase == null)
+ {
+ return null;
+ }
+ if ("APPLY_REQUEST_VALUES".equals(phase))
+ {
+ return PhaseId.APPLY_REQUEST_VALUES;
+ }
+ else if ("PROCESS_VALIDATIONS".equals(phase))
+ {
+ return PhaseId.PROCESS_VALIDATIONS;
+ }
+ else if ("UPDATE_MODEL_VALUES".equals(phase))
+ {
+ return PhaseId.UPDATE_MODEL_VALUES;
+ }
+ else if ("INVOKE_APPLICATION".equals(phase))
+ {
+ return PhaseId.INVOKE_APPLICATION;
+ }
+ else if ("ANY_PHASE".equals(phase) || "RESTORE_VIEW".equals(phase) || "RENDER_REPONSE".equals(phase))
+ {
+ throw new FacesException("View actions cannot be executed in specified phase: [" + phase + "]");
+ }
+ else
+ {
+ throw new FacesException("Not a valid phase [" + phase + "]");
+ }
+ }
+
+ /**
+ * Action listeners are not supported by the {@link UIViewAction} component.
+ *
+ * @throws UnsupportedOperationException if called
+ */
+ public void addActionListener(final ActionListener listener)
+ {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ /**
+ * Action listeners are not supported by the {@link UIViewAction} component.
+ */
+ public ActionListener[] getActionListeners()
+ {
+ return new ActionListener[0];
+ }
+
+ /**
+ * Action listeners are not supported by the {@link UIViewAction} component.
+ *
+ * @throws UnsupportedOperationException if called
+ */
+ public void removeActionListener(final ActionListener listener)
+ {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ /**
+ * Returns the action, represented as an EL method expression, to invoke.
+ */
+ public MethodExpression getActionExpression()
+ {
+ return (MethodExpression) getStateHelper().get(PropertyKeys.actionExpression);
+ }
+
+ /**
+ * Sets the action, represented as an EL method expression, to invoke.
+ */
+ public void setActionExpression(final MethodExpression actionExpression)
+ {
+ getStateHelper().put(PropertyKeys.actionExpression, actionExpression);
+ }
+
+ /**
+ * Returns a boolean value that controls whether the action is invoked during
+ * faces (postback) request. The default is false.
+ */
+ public boolean isOnPostback()
+ {
+ return (Boolean) getStateHelper().eval(PropertyKeys.onPostback, false);
+ }
+
+ /**
+ * Set the bookean flag that controls whether the action is invoked during a
+ * faces (postback) request.
+ */
+ public void setOnPostback(final boolean onPostback)
+ {
+ getStateHelper().put(PropertyKeys.onPostback, onPostback);
+ }
+
+ /**
+ * Returns a condition, represented as an EL value expression, that must
+ * evaluate to true for the action to be invoked.
+ */
+ public boolean isIf()
+ {
+ return (Boolean) getStateHelper().eval(PropertyKeys.ifAttr, true);
+ }
+
+ /**
+ * Sets the condition, represented as an EL value expression, that must
+ * evaluate to true for the action to be invoked.
+ */
+ public void setIf(final boolean condition)
+ {
+ getStateHelper().put(PropertyKeys.ifAttr, condition);
+ }
+
+ // ----------------------------------------------------- UIComponent Methods
+ /**
+ * <p>
+ * In addition to to the default {@link UIComponent#broadcast} processing,
+ * pass the {@link ActionEvent} being broadcast to the default
+ * {@link ActionListener} registered on the
+ * {@link javax.faces.application.Application}.
+ * </p>
+ *
+ * @param event {@link FacesEvent} to be broadcast
+ *
+ * @throws AbortProcessingException Signal the JavaServer Faces
+ * implementation that no further processing on the current event
+ * should be performed
+ * @throws IllegalArgumentException if the implementation class of this
+ * {@link FacesEvent} is not supported by this component
+ * @throws NullPointerException if <code>event</code> is <code>null</code>
+ */
+ @Override
+ public void broadcast(final FacesEvent event) throws AbortProcessingException
+ {
+
+ super.broadcast(event);
+
+ FacesContext context = getFacesContext();
+
+ // OPEN QUESTION: should we consider a navigation to the same view as a
+ // no-op navigation?
+
+ // only proceed if the response has not been marked complete and
+ // navigation to another view has not occurred
+ if ((event instanceof ActionEvent) && !context.getResponseComplete() && (context.getViewRoot() == getViewRootOf(event)))
+ {
+ ActionListener listener = context.getApplication().getActionListener();
+ if (listener != null)
+ {
+ UIViewRoot viewRootBefore = context.getViewRoot();
+ InstrumentedFacesContext instrumentedContext = new InstrumentedFacesContext(context);
+ // defer the call to renderResponse() that happens in
+ // ActionListener#processAction(ActionEvent)
+ instrumentedContext.disableRenderResponseControl().set();
+ listener.processAction((ActionEvent) event);
+ instrumentedContext.restore();
+ // if the response is marked complete, the story is over
+ if (!context.getResponseComplete())
+ {
+ UIViewRoot viewRootAfter = context.getViewRoot();
+ // if the view id changed as a result of navigation, then execute
+ // the JSF lifecycle for the new view id
+ if (viewRootBefore != viewRootAfter)
+ {
+ /*
+ * // execute the JSF lifecycle by dispatching a forward
+ * request // this approach is problematic because it throws a
+ * wrench in the event broadcasting try {
+ * context.getExternalContext
+ * ().dispatch(context.getApplication()
+ * .getViewHandler().getActionURL(context,
+ * viewRootAfter.getViewId())
+ * .substring(context.getExternalContext
+ * ().getRequestContextPath().length())); // kill this
+ * lifecycle execution context.responseComplete(); } catch
+ * (IOException e) { throw new
+ * FacesException("Dispatch to viewId failed: " +
+ * viewRootAfter.getViewId(), e); }
+ */
+
+ // manually execute the JSF lifecycle on the new view id
+ // certain tweaks have to be made to the FacesContext to allow
+ // us to reset the lifecycle
+ Lifecycle lifecycle = getLifecycle(context);
+ instrumentedContext = new InstrumentedFacesContext(context);
+ instrumentedContext.pushViewIntoRequestMap().clearViewRoot().clearPostback().set();
+ lifecycle.execute(instrumentedContext);
+ instrumentedContext.restore();
+
+ /*
+ * Another approach would be to register a phase listener in
+ * the decode() method for the phase in which the action is
+ * set to invoke. The phase listener would performs a servlet
+ * forward if a non-redirect navigation occurs after the
+ * phase.
+ */
+ }
+ else
+ {
+ // apply the deferred call (relevant when immediate is true)
+ context.renderResponse();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * First, determine if the action should be invoked by evaluating this
+ * components pre-conditions. If this is a faces (postback) request and the
+ * evaluated value of the postback attribute is false, take no action. If the
+ * evaluated value of the if attribute is false, take no action. If both
+ * conditions pass, proceed with creating an {@link ActionEvent}.
+ *
+ * Set the phaseId in which the queued {@link ActionEvent} should be
+ * broadcast by assigning the appropriate value to the phaseId property of
+ * the {@link ActionEvent} according to the evaluated value of the immediate
+ * attribute. If the value is <literal>true</literal>, set the phaseId to
+ * {@link PhaseId#APPLY_REQUEST_VALUES}. Otherwise, set the phaseId to to
+ * {@link PhaseId#INVOKE_APPLICATION}.
+ *
+ * Finally, queue the event by calling <literal>queueEvent()</literal> and
+ * passing the {@link ActionEvent} just created.
+ */
+ @Override
+ public void decode(final FacesContext context)
+ {
+ if (context == null)
+ {
+ throw new NullPointerException();
+ }
+
+ if ((context.isPostback() && !isOnPostback()) || !isIf())
+ {
+ return;
+ }
+
+ ActionEvent e = new ActionEvent(this);
+ PhaseId phaseId = getPhaseId();
+ if (phaseId != null)
+ {
+ e.setPhaseId(phaseId);
+ }
+ else if (isImmediate())
+ {
+ e.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
+ }
+ else
+ {
+ e.setPhaseId(PhaseId.INVOKE_APPLICATION);
+ }
+
+ queueEvent(e);
+ }
+
+ private UIViewRoot getViewRootOf(final FacesEvent e)
+ {
+ UIComponent c = e.getComponent();
+ do
+ {
+ if (c instanceof UIViewRoot)
+ {
+ return (UIViewRoot) c;
+ }
+ c = c.getParent();
+ }
+ while (c != null);
+ return null;
+ }
+
+ private Lifecycle getLifecycle(final FacesContext context)
+ {
+ LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+ String lifecycleId = context.getExternalContext().getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
+ if (lifecycleId == null)
+ {
+ lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
+ }
+ return lifecycleFactory.getLifecycle(lifecycleId);
+ }
+
+ /**
+ * A FacesContext delegator that gives us the necessary controls over the
+ * FacesContext to allow the execution of the lifecycle to accomodate the
+ * UIViewAction sequence.
+ */
+ private class InstrumentedFacesContext extends FacesContextWrapper
+ {
+
+ private final FacesContext wrapped;
+ private boolean viewRootCleared = false;
+ private boolean renderedResponseControlDisabled = false;
+ private Boolean postback = null;
+
+ public InstrumentedFacesContext(final FacesContext wrapped)
+ {
+ this.wrapped = wrapped;
+ }
+
+ @Override
+ public FacesContext getWrapped()
+ {
+ return wrapped;
+ }
+
+ @Override
+ public UIViewRoot getViewRoot()
+ {
+ if (viewRootCleared)
+ {
+ return null;
+ }
+
+ return wrapped.getViewRoot();
+ }
+
+ @Override
+ public void setViewRoot(final UIViewRoot viewRoot)
+ {
+ viewRootCleared = false;
+ wrapped.setViewRoot(viewRoot);
+ }
+
+ @Override
+ public boolean isPostback()
+ {
+ return postback == null ? wrapped.isPostback() : postback;
+ }
+
+ @Override
+ public void renderResponse()
+ {
+ if (!renderedResponseControlDisabled)
+ {
+ wrapped.renderResponse();
+ }
+ }
+
+ /**
+ * Make it look like we have dispatched a request using the include
+ * method.
+ */
+ public InstrumentedFacesContext pushViewIntoRequestMap()
+ {
+ getExternalContext().getRequestMap().put("javax.servlet.include.servlet_path", wrapped.getViewRoot().getViewId());
+ return this;
+ }
+
+ public InstrumentedFacesContext clearPostback()
+ {
+ postback = false;
+ return this;
+ }
+
+ public InstrumentedFacesContext clearViewRoot()
+ {
+ viewRootCleared = true;
+ return this;
+ }
+
+ public InstrumentedFacesContext disableRenderResponseControl()
+ {
+ renderedResponseControlDisabled = true;
+ return this;
+ }
+
+ public void set()
+ {
+ setCurrentInstance(this);
+ }
+
+ public void restore()
+ {
+ setCurrentInstance(wrapped);
+ }
+ }
+}
Added: modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/ValueExpressionAnalyzer.java
===================================================================
--- modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/ValueExpressionAnalyzer.java (rev 0)
+++ modules/faces/trunk/api/src/main/java/org/jboss/seam/faces/component/ValueExpressionAnalyzer.java 2010-05-28 23:06:51 UTC (rev 12896)
@@ -0,0 +1,175 @@
+package org.jboss.seam.faces.component;
+
+import java.beans.FeatureDescriptor;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.ELResolver;
+import javax.el.FunctionMapper;
+import javax.el.ValueExpression;
+import javax.el.ValueReference;
+import javax.el.VariableMapper;
+import javax.faces.el.CompositeComponentExpressionHolder;
+
+/**
+ * Analyzes a {@link ValueExpression} and provides access to the base object and property
+ * name to which the expression maps via the getReference() method.
+ */
+class ValueExpressionAnalyzer
+{
+ private ValueExpression expression;
+
+ public ValueExpressionAnalyzer(ValueExpression expression)
+ {
+ this.expression = expression;
+ }
+
+ public ValueReference getValueReference(ELContext elContext)
+ {
+ InterceptingResolver resolver = new InterceptingResolver(elContext.getELResolver());
+ try
+ {
+ expression.setValue(decorateELContext(elContext, resolver), null);
+ }
+ catch (ELException ele)
+ {
+ return null;
+ }
+ ValueReference reference = resolver.getValueReference();
+ if (reference != null)
+ {
+ Object base = reference.getBase();
+ if (base instanceof CompositeComponentExpressionHolder)
+ {
+ ValueExpression ve = ((CompositeComponentExpressionHolder) base).getExpression((String) reference.getProperty());
+ if (ve != null)
+ {
+ this.expression = ve;
+ reference = getValueReference(elContext);
+ }
+ }
+ }
+ return reference;
+ }
+
+ private ELContext decorateELContext(final ELContext context, final ELResolver resolver)
+ {
+ return new ELContext()
+ {
+ // punch in our new ELResolver
+ @Override
+ public ELResolver getELResolver()
+ {
+ return resolver;
+ }
+
+ // The rest of the methods simply delegate to the existing context
+ @Override
+ public Object getContext(Class key)
+ {
+ return context.getContext(key);
+ }
+
+ @Override
+ public Locale getLocale()
+ {
+ return context.getLocale();
+ }
+
+ @Override
+ public boolean isPropertyResolved()
+ {
+ return context.isPropertyResolved();
+ }
+
+ @Override
+ public void putContext(Class key, Object contextObject)
+ {
+ context.putContext(key, contextObject);
+ }
+
+ @Override
+ public void setLocale(Locale locale)
+ {
+ context.setLocale(locale);
+ }
+
+ @Override
+ public void setPropertyResolved(boolean resolved)
+ {
+ context.setPropertyResolved(resolved);
+ }
+
+ @Override
+ public FunctionMapper getFunctionMapper()
+ {
+ return context.getFunctionMapper();
+ }
+
+ @Override
+ public VariableMapper getVariableMapper()
+ {
+ return context.getVariableMapper();
+ }
+ };
+ }
+
+ private static class InterceptingResolver extends ELResolver
+ {
+ private ELResolver delegate;
+ private ValueReference valueReference;
+
+ public InterceptingResolver(ELResolver delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ public ValueReference getValueReference()
+ {
+ return valueReference;
+ }
+
+ // Capture the base and property rather than write the value
+ @Override
+ public void setValue(ELContext context, Object base, Object property, Object value)
+ {
+ if (base != null && property != null)
+ {
+ context.setPropertyResolved(true);
+ valueReference = new ValueReference(base, property.toString());
+ }
+ }
+
+ // The rest of the methods simply delegate to the existing context
+ @Override
+ public Object getValue(ELContext context, Object base, Object property)
+ {
+ return delegate.getValue(context, base, property);
+ }
+
+ @Override
+ public Class<?> getType(ELContext context, Object base, Object property)
+ {
+ return delegate.getType(context, base, property);
+ }
+
+ @Override
+ public boolean isReadOnly(ELContext context, Object base, Object property)
+ {
+ return delegate.isReadOnly(context, base, property);
+ }
+
+ @Override
+ public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base)
+ {
+ return delegate.getFeatureDescriptors(context, base);
+ }
+
+ @Override
+ public Class<?> getCommonPropertyType(ELContext context, Object base)
+ {
+ return delegate.getCommonPropertyType(context, base);
+ }
+ }
+}
Added: modules/faces/trunk/api/src/main/resources/META-INF/faces-config.xml
===================================================================
--- modules/faces/trunk/api/src/main/resources/META-INF/faces-config.xml (rev 0)
+++ modules/faces/trunk/api/src/main/resources/META-INF/faces-config.xml 2010-05-28 23:06:51 UTC (rev 12896)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
+ version="2.0">
+ <!-- This file is present to allow annotated component classes to be discovered and registered -->
+</faces-config>
Deleted: modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/MethodBindingMethodExpressionAdapter.java
===================================================================
--- modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/MethodBindingMethodExpressionAdapter.java 2010-05-28 20:39:48 UTC (rev 12895)
+++ modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/MethodBindingMethodExpressionAdapter.java 2010-05-28 23:06:51 UTC (rev 12896)
@@ -1,339 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2010, Red Hat, Inc., and individual contributors
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.seam.faces.component;
-
-import java.io.Serializable;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-
-import javax.el.ELContext;
-import javax.el.ELException;
-import javax.el.ExpressionFactory;
-import javax.el.MethodExpression;
-import javax.el.MethodInfo;
-import javax.el.ValueExpression;
-import javax.faces.component.StateHolder;
-import javax.faces.context.FacesContext;
-import javax.faces.el.EvaluationException;
-import javax.faces.el.MethodBinding;
-import javax.faces.el.MethodNotFoundException;
-
-/**
- * <p>
- * Wrap a MethodExpression instance and expose it as a MethodBinding
- * </p>
- *
- */
-class MethodBindingMethodExpressionAdapter extends MethodBinding implements StateHolder, Serializable
-{
-
- private static final long serialVersionUID = 7334926223014401689L;
- private MethodExpression methodExpression = null;
- private boolean tranzient;
-
- public MethodBindingMethodExpressionAdapter()
- {
- } // for StateHolder
-
- MethodBindingMethodExpressionAdapter(final MethodExpression methodExpression)
- {
- this.methodExpression = methodExpression;
- }
-
- @Override
- @SuppressWarnings("deprecation")
- public Object invoke(final FacesContext context, final Object params[]) throws EvaluationException, MethodNotFoundException
- {
- assert (null != methodExpression);
- if (context == null)
- {
- throw new NullPointerException("FacesConext -> null");
- }
-
- Object result = null;
- try
- {
- result = methodExpression.invoke(context.getELContext(), params);
- }
- catch (javax.el.MethodNotFoundException e)
- {
- throw new javax.faces.el.MethodNotFoundException(e);
- }
- catch (javax.el.PropertyNotFoundException e)
- {
- throw new EvaluationException(e);
- }
- catch (ELException e)
- {
- Throwable cause = e.getCause();
- if (cause == null)
- {
- cause = e;
- }
- throw new EvaluationException(cause);
- }
- catch (NullPointerException e)
- {
- throw new MethodNotFoundException(e);
- }
- return result;
- }
-
- @Override
- @SuppressWarnings("deprecation")
- public Class<?> getType(final FacesContext context) throws MethodNotFoundException
- {
- assert (null != methodExpression);
- if (context == null)
- {
- throw new NullPointerException("FacesConext -> null");
- }
- Class<?> result = null;
- if (context == null)
- {
- throw new NullPointerException();
- }
-
- try
- {
- MethodInfo mi = methodExpression.getMethodInfo(context.getELContext());
- result = mi.getReturnType();
- }
- catch (javax.el.PropertyNotFoundException e)
- {
- throw new MethodNotFoundException(e);
- }
- catch (javax.el.MethodNotFoundException e)
- {
- throw new MethodNotFoundException(e);
- }
- catch (ELException e)
- {
- throw new MethodNotFoundException(e);
- }
- return result;
- }
-
- @Override
- public String getExpressionString()
- {
- assert (null != methodExpression);
- return methodExpression.getExpressionString();
- }
-
- @Override
- @SuppressWarnings("deprecation")
- public boolean equals(final Object other)
- {
- if (this == other)
- {
- return true;
- }
- if (other instanceof MethodBindingMethodExpressionAdapter)
- {
- return methodExpression.equals(((MethodBindingMethodExpressionAdapter) other).getWrapped());
- }
- else if (other instanceof MethodBinding)
- {
- MethodBinding binding = (MethodBinding) other;
-
- // We'll need to do a little leg work to determine
- // if the MethodBinding is equivalent to the
- // wrapped MethodExpression
- String expr = binding.getExpressionString();
- int idx = expr.indexOf('.');
- String target = expr.substring(0, idx).substring(2);
- String t = expr.substring(idx + 1);
- String method = t.substring(0, (t.length() - 1));
-
- FacesContext context = FacesContext.getCurrentInstance();
- ELContext elContext = context.getELContext();
- MethodInfo controlInfo = methodExpression.getMethodInfo(elContext);
-
- // ensure the method names are the same
- if (!controlInfo.getName().equals(method))
- {
- return false;
- }
-
- // Using the target, create an expression and evaluate
- // it.
- ExpressionFactory factory = context.getApplication().getExpressionFactory();
- ValueExpression ve = factory.createValueExpression(elContext, "#{" + target + '}', Object.class);
- if (ve == null)
- {
- return false;
- }
-
- Object result = ve.getValue(elContext);
-
- if (result == null)
- {
- return false;
- }
-
- // Get all of the methods with the matching name and try
- // to find a match based on controlInfo's return and parameter
- // types
- Class<?> type = binding.getType(context);
- Method[] methods = result.getClass().getMethods();
- for (Method meth : methods)
- {
- if (meth.getName().equals(method) && type.equals(controlInfo.getReturnType()) && Arrays.equals(meth.getParameterTypes(), controlInfo.getParamTypes()))
- {
- return true;
- }
- }
- }
-
- return false;
-
- }
-
- @Override
- public int hashCode()
- {
- assert (null != methodExpression);
-
- return methodExpression.hashCode();
- }
-
- public boolean isTransient()
- {
- return this.tranzient;
- }
-
- public void setTransient(final boolean tranzient)
- {
- this.tranzient = tranzient;
- }
-
- public Object saveState(final FacesContext context)
- {
- if (context == null)
- {
- throw new NullPointerException();
- }
- Object result = null;
- if (!tranzient)
- {
- if (methodExpression instanceof StateHolder)
- {
- Object[] stateStruct = new Object[2];
-
- // save the actual state of our wrapped methodExpression
- stateStruct[0] = ((StateHolder) methodExpression).saveState(context);
- // save the class name of the methodExpression impl
- stateStruct[1] = methodExpression.getClass().getName();
-
- result = stateStruct;
- }
- else
- {
- result = methodExpression;
- }
- }
-
- return result;
-
- }
-
- public void restoreState(final FacesContext context, final Object state)
- {
- if (context == null)
- {
- throw new NullPointerException();
- }
- // if we have state
- if (null == state)
- {
- return;
- }
-
- if (!(state instanceof MethodExpression))
- {
- Object[] stateStruct = (Object[]) state;
- Object savedState = stateStruct[0];
- String className = stateStruct[1].toString();
- MethodExpression result = null;
-
- Class<?> toRestoreClass = null;
- if (null != className)
- {
- try
- {
- toRestoreClass = loadClass(className, this);
- }
- catch (ClassNotFoundException e)
- {
- throw new IllegalStateException(e.getMessage());
- }
-
- if (null != toRestoreClass)
- {
- try
- {
- result = (MethodExpression) toRestoreClass.newInstance();
- }
- catch (InstantiationException e)
- {
- throw new IllegalStateException(e.getMessage());
- }
- catch (IllegalAccessException a)
- {
- throw new IllegalStateException(a.getMessage());
- }
- }
-
- if ((null != result) && (null != savedState))
- {
- // don't need to check transient, since that was
- // done on the saving side.
- ((StateHolder) result).restoreState(context, savedState);
- }
- methodExpression = result;
- }
- }
- else
- {
- methodExpression = (MethodExpression) state;
- }
- }
-
- public MethodExpression getWrapped()
- {
- return methodExpression;
- }
-
- //
- // Helper methods for StateHolder
- //
- private static Class<?> loadClass(final String name, final Object fallbackClass) throws ClassNotFoundException
- {
- ClassLoader loader = Thread.currentThread().getContextClassLoader();
- if (loader == null)
- {
- loader = fallbackClass.getClass().getClassLoader();
- }
- return Class.forName(name, true, loader);
- }
-}
\ No newline at end of file
Deleted: modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/UIValidateForm.java
===================================================================
--- modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/UIValidateForm.java 2010-05-28 20:39:48 UTC (rev 12895)
+++ modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/UIValidateForm.java 2010-05-28 23:06:51 UTC (rev 12896)
@@ -1,183 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2010, Red Hat, Inc., and individual contributors
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-package org.jboss.seam.faces.component;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.enterprise.inject.spi.BeanManager;
-import javax.enterprise.util.AnnotationLiteral;
-import javax.faces.component.FacesComponent;
-import javax.faces.component.UIComponent;
-import javax.faces.component.UIForm;
-import javax.faces.component.UIInput;
-import javax.faces.component.UIViewRoot;
-import javax.faces.context.FacesContext;
-import javax.faces.event.PostValidateEvent;
-import javax.faces.event.PreValidateEvent;
-import javax.faces.validator.Validator;
-import javax.faces.validator.ValidatorException;
-
-import org.jboss.seam.faces.event.qualifier.After;
-import org.jboss.seam.faces.event.qualifier.Before;
-import org.jboss.weld.extensions.beanManager.BeanManagerAccessor;
-
-/**
- * @author <a href="mailto:lincolnbaxter at gmail.com>Lincoln Baxter, III</a>
- *
- */
- at FacesComponent(UIValidateForm.COMPONENT_TYPE)
-public class UIValidateForm extends UIInput
-{
- private static final AnnotationLiteral<Before> BEFORE = new AnnotationLiteral<Before>()
- {
- private static final long serialVersionUID = 7631699535063526392L;
- };
- private static final AnnotationLiteral<After> AFTER = new AnnotationLiteral<After>()
- {
- private static final long serialVersionUID = -929128236303355107L;
- };
-
- public static final String COMPONENT_TYPE = "org.jboss.seam.faces.ValidateForm";
- public static final String COMPONENT_FAMILY = "org.jboss.seam.faces.ValidateForm";
-
- private String validatorId = "";
- private String fields = "";
- private Map<String, UIInput> components = new HashMap<String, UIInput>();
-
- @Override
- public String getFamily()
- {
- return COMPONENT_FAMILY;
- }
-
- @Override
- public void validate(final FacesContext context)
- {
- context.getApplication().publishEvent(context, PreValidateEvent.class, UIValidateForm.class, this);
- BeanManager manager = BeanManagerAccessor.getManager();
- manager.fireEvent(this, BEFORE);
-
- Validator validator = context.getApplication().createValidator(validatorId);
- if (validator == null)
- {
- throw new IllegalArgumentException("Could not create Validator with id: [" + validatorId + "]");
- }
-
- try
- {
- UIComponent parent = this.getParent();
- validator.validate(context, parent, components);
- }
- catch (ValidatorException e)
- {
- setValid(false);
- for (UIInput comp : components.values())
- {
- comp.setValid(false);
- // TODO Put this back when attributes can control it
- // context.addMessage(comp.getClientId(), e.getFacesMessage());
- }
- context.addMessage(null, e.getFacesMessage());
- }
-
- manager.fireEvent(this, AFTER);
- context.getApplication().publishEvent(context, PostValidateEvent.class, UIValidateForm.class, this);
- }
-
- /**
- * Attempt to locate the form in which this component resides. If the
- * component is not within a UIForm tag, throw an exception.
- */
- public UIForm locateForm()
- {
- UIComponent parent = this.getParent();
- while (!(parent instanceof UIForm))
- {
- if ((parent == null) || (parent instanceof UIViewRoot))
- {
- throw new IllegalStateException("The UIValidateForm (<s:validateForm />) component must be placed within a UIForm (<h:form>)");
- }
- parent = parent.getParent();
- }
- return (UIForm) parent;
- }
-
- /*
- * Prevent any rendered output.
- */
-
- @Override
- public void encodeAll(final FacesContext context) throws IOException
- {
- locateForm();
- }
-
- @Override
- public void encodeBegin(final FacesContext context) throws IOException
- {
- }
-
- @Override
- public void encodeEnd(final FacesContext context) throws IOException
- {
- }
-
- @Override
- public void encodeChildren(final FacesContext context) throws IOException
- {
- }
-
- /*
- * Getters & Setters
- */
-
- public String getFields()
- {
- return fields;
- }
-
- public void setFields(final String fields)
- {
- this.fields = fields;
- }
-
- public String getValidatorId()
- {
- return validatorId;
- }
-
- public void setValidatorId(final String validatorId)
- {
- this.validatorId = validatorId;
- }
-
- /**
- * @param components
- */
- public void setComponents(final Map<String, UIInput> components)
- {
- this.components = components;
- }
-}
Deleted: modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/UIViewAction.java
===================================================================
--- modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/UIViewAction.java 2010-05-28 20:39:48 UTC (rev 12895)
+++ modules/faces/trunk/impl/src/main/java/org/jboss/seam/faces/component/UIViewAction.java 2010-05-28 23:06:51 UTC (rev 12896)
@@ -1,677 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2010, Red Hat, Inc., and individual contributors
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.seam.faces.component;
-
-import javax.el.MethodExpression;
-import javax.faces.FacesException;
-import javax.faces.FactoryFinder;
-import javax.faces.application.NavigationHandler;
-import javax.faces.component.ActionSource2;
-import javax.faces.component.FacesComponent;
-import javax.faces.component.UICommand;
-import javax.faces.component.UIComponent;
-import javax.faces.component.UIComponentBase;
-import javax.faces.component.UIViewParameter;
-import javax.faces.component.UIViewRoot;
-import javax.faces.context.FacesContext;
-import javax.faces.context.FacesContextWrapper;
-import javax.faces.el.MethodBinding;
-import javax.faces.event.AbortProcessingException;
-import javax.faces.event.ActionEvent;
-import javax.faces.event.ActionListener;
-import javax.faces.event.FacesEvent;
-import javax.faces.event.PhaseId;
-import javax.faces.event.PreRenderViewEvent;
-import javax.faces.lifecycle.Lifecycle;
-import javax.faces.lifecycle.LifecycleFactory;
-import javax.faces.view.ViewMetadata;
-import javax.faces.webapp.FacesServlet;
-
-/**
- * <p>
- * <strong>UIViewAction</strong> is an {@link ActionSource2} {@link UIComponent}
- * that specifies an application-specific command (or action)--defined as an EL
- * method expression--to be invoked during one of the JSF lifecycle phases that
- * proceeds view rendering. This component must be declared as a child of the
- * {@link ViewMetadata} facet of the {@link UIViewRoot} so that it gets
- * incorporated into the JSF lifecycle on both non-faces (initial) requests and
- * faces (postback) requests.
- * </p>
- *
- * <p>
- * The purpose of this component is to provide a light-weight front-controller
- * solution for executing code upon the loading of a JSF view to support the
- * integration of system services, content retrieval, view management, and
- * navigation. This functionality is especially useful for non-faces (initial)
- * requests.
- * </p>
- *
- * <p>
- * The {@link UIViewAction} component is closely tied to the
- * {@link UIViewParameter} component. The {@link UIViewParameter} component
- * binds a request parameter to a model property. Most of the time, this binding
- * is used to populate the model with data that supports the method being
- * invoked by a {@link UIViewAction} component, much like form inputs populate
- * the model with data to support the method being invoked by a
- * {@link UICommand} component.
- * </p>
- *
- * <p>
- * When the <literal>decode()</literal> method of the {@link UIViewAction} is
- * invoked, it will queue an {@link ActionEvent} to be broadcast to all
- * interested listeners when the <literal>broadcast()</literal> method is
- * invoked.
- * </p>
- *
- * <p>
- * If the value of the component's <literal>immediate</literal> attribute is
- * <literal>true</literal>, the action will be invoked during the Apply Request
- * Values JSF lifecycle phase. Otherwise, the action will be invoked during the
- * Invoke Application phase, the default behavior. The phase cannot be set
- * explicitly in the <literal>phase</literal> attribute, which takes precedence
- * over the <literal>immediate</literal> attribute.
- * </p>
- *
- * <p>
- * The invocation of the action is normally suppressed (meaning the
- * {@link ActionEvent} is not queued) on a faces request. It can be enabled by
- * setting the component's <literal>onPostback</literal> attribute to
- * <literal>true</literal>. Execution of the method can be subject to a required
- * condition for all requests by assigning an EL value expression of expected
- * type boolean to the component's <literal>if</literal> attribute, which must
- * evaluate to <literal>true</literal> for the action to be invoked.
- * </p>
- *
- * <p>
- * The {@link NavigationHandler} is consulted after the action is invoked to
- * carry out the navigation case that matches the action signature and outcome.
- * If a navigation case is matched, or the response is marked complete by the
- * action, subsequent {@link UIViewAction} components associated with the
- * current view are short-circuited. The lifecycle then advances appropriately.
- * </p>
- *
- * <p>
- * It's important to note that the full component tree is not built before the
- * UIViewAction components are processed on an non-faces (initial) request.
- * Rather, the component tree only contains the {@link ViewMetadata}, an
- * important part of the optimization of this component and what sets it apart
- * from a {@link PreRenderViewEvent} listener.
- * </p>
- *
- * @author Dan Allen
- * @author Andy Schwartz
- *
- * @see UIViewParameter
- */
- at FacesComponent(
-// tagName = "viewAction",
-// namespace = "http://jboss.org/seam/faces",
-// (see
-// https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=594)
-value = UIViewAction.COMPONENT_TYPE)
-public class UIViewAction extends UIComponentBase implements ActionSource2
-{
-
- // ------------------------------------------------------ Manifest Constants
-
- /**
- * <p>
- * The standard component type for this component.
- * </p>
- */
- public static final String COMPONENT_TYPE = "org.jboss.seam.faces.ViewAction";
-
- /**
- * <p>
- * The standard component family for this component.
- * </p>
- */
- public static final String COMPONENT_FAMILY = "org.jboss.seam.faces.ViewAction";
-
- /**
- * Properties that are tracked by state saving.
- */
- enum PropertyKeys
- {
-
- onPostback, actionExpression, immediate, phase, ifAttr("if");
- private String name;
-
- PropertyKeys()
- {
- }
-
- PropertyKeys(final String name)
- {
- this.name = name;
- }
-
- @Override
- public String toString()
- {
- return name != null ? name : super.toString();
- }
- }
-
- // ------------------------------------------------------------ Constructors
- /**
- * <p>
- * Create a new {@link UIViewAction} instance with default property values.
- * </p>
- */
- public UIViewAction()
- {
- super();
- setRendererType(null);
- }
-
- // -------------------------------------------------------------- Properties
- @Override
- public String getFamily()
- {
- return COMPONENT_FAMILY;
- }
-
- /**
- * {@inheritDoc}
- *
- * @deprecated This has been replaced by {@link #getActionExpression}.
- */
- @Deprecated
- public MethodBinding getAction()
- {
- MethodBinding result = null;
- MethodExpression me;
-
- if (null != (me = getActionExpression()))
- {
- result = new MethodBindingMethodExpressionAdapter(me);
- }
- return result;
- }
-
- /**
- * {@inheritDoc}
- *
- * @deprecated This has been replaced by
- * {@link #setActionExpression(javax.el.MethodExpression)}.
- * @throws UnsupportedOperationException if called
- */
- @Deprecated
- public void setAction(final MethodBinding action)
- {
- throw new UnsupportedOperationException("Not supported.");
- }
-
- /**
- * Action listeners are not supported by the {@link UIViewAction} component.
- *
- * @throws UnsupportedOperationException if called
- */
- @SuppressWarnings("deprecation")
- public MethodBinding getActionListener()
- {
- throw new UnsupportedOperationException("Not supported.");
- }
-
- /**
- * Action listeners are not supported by the {@link UIViewAction} component.
- *
- * @throws UnsupportedOperationException if called
- */
- @SuppressWarnings("deprecation")
- public void setActionListener(final MethodBinding actionListener)
- {
- throw new UnsupportedOperationException("Not supported.");
- }
-
- /**
- * Returns the value which dictates the JSF lifecycle phase in which the
- * action is invoked. If the value of this attribute is
- * <literal>true</literal>, the action will be invoked in the Apply Request
- * Values phase. If the value of this attribute is <literal>false</literal>,
- * the default, the action will be invoked in the Invoke Application Phase.
- */
- public boolean isImmediate()
- {
- return (Boolean) getStateHelper().eval(PropertyKeys.immediate, false);
- }
-
- /**
- * Sets the immediate flag, which controls the JSF lifecycle in which the
- * action is invoked.
- */
- public void setImmediate(final boolean immediate)
- {
- getStateHelper().put(PropertyKeys.immediate, immediate);
- }
-
- /**
- * <p>
- * Returns the name of the phase in which the action is to be queued. Only
- * the following phases are supported (case does not matter):
- * </p>
- * <ul>
- * <li>APPLY_REQUEST_VALUES</li>
- * <li>PROCESS_VALIDATIONS</li>
- * <li>UPDATE_MODEL_VALUES</li>
- * <li>INVOKE_APPLICATION</li>
- * </ul>
- * <p>
- * If the phase is set, it takes precedence over the immediate flag.
- * </p>
- */
- public String getPhase()
- {
- String phase = (String) getStateHelper().eval(PropertyKeys.phase);
- if (phase != null)
- {
- phase = phase.toUpperCase();
- }
- return phase;
- }
-
- /**
- * Set the name of the phase in which the action is to be queued.
- */
- public void setPhase(final String phase)
- {
- getStateHelper().put(PropertyKeys.phase, phase);
- }
-
- public PhaseId getPhaseId()
- {
- String phase = getPhase();
- if (phase == null)
- {
- return null;
- }
- if ("APPLY_REQUEST_VALUES".equals(phase))
- {
- return PhaseId.APPLY_REQUEST_VALUES;
- }
- else if ("PROCESS_VALIDATIONS".equals(phase))
- {
- return PhaseId.PROCESS_VALIDATIONS;
- }
- else if ("UPDATE_MODEL_VALUES".equals(phase))
- {
- return PhaseId.UPDATE_MODEL_VALUES;
- }
- else if ("INVOKE_APPLICATION".equals(phase))
- {
- return PhaseId.INVOKE_APPLICATION;
- }
- else if ("ANY_PHASE".equals(phase) || "RESTORE_VIEW".equals(phase) || "RENDER_REPONSE".equals(phase))
- {
- throw new FacesException("View actions cannot be executed in specified phase: [" + phase + "]");
- }
- else
- {
- throw new FacesException("Not a valid phase [" + phase + "]");
- }
- }
-
- /**
- * Action listeners are not supported by the {@link UIViewAction} component.
- *
- * @throws UnsupportedOperationException if called
- */
- public void addActionListener(final ActionListener listener)
- {
- throw new UnsupportedOperationException("Not supported.");
- }
-
- /**
- * Action listeners are not supported by the {@link UIViewAction} component.
- */
- public ActionListener[] getActionListeners()
- {
- return new ActionListener[0];
- }
-
- /**
- * Action listeners are not supported by the {@link UIViewAction} component.
- *
- * @throws UnsupportedOperationException if called
- */
- public void removeActionListener(final ActionListener listener)
- {
- throw new UnsupportedOperationException("Not supported.");
- }
-
- /**
- * Returns the action, represented as an EL method expression, to invoke.
- */
- public MethodExpression getActionExpression()
- {
- return (MethodExpression) getStateHelper().get(PropertyKeys.actionExpression);
- }
-
- /**
- * Sets the action, represented as an EL method expression, to invoke.
- */
- public void setActionExpression(final MethodExpression actionExpression)
- {
- getStateHelper().put(PropertyKeys.actionExpression, actionExpression);
- }
-
- /**
- * Returns a boolean value that controls whether the action is invoked during
- * faces (postback) request. The default is false.
- */
- public boolean isOnPostback()
- {
- return (Boolean) getStateHelper().eval(PropertyKeys.onPostback, false);
- }
-
- /**
- * Set the bookean flag that controls whether the action is invoked during a
- * faces (postback) request.
- */
- public void setOnPostback(final boolean onPostback)
- {
- getStateHelper().put(PropertyKeys.onPostback, onPostback);
- }
-
- /**
- * Returns a condition, represented as an EL value expression, that must
- * evaluate to true for the action to be invoked.
- */
- public boolean isIf()
- {
- return (Boolean) getStateHelper().eval(PropertyKeys.ifAttr, true);
- }
-
- /**
- * Sets the condition, represented as an EL value expression, that must
- * evaluate to true for the action to be invoked.
- */
- public void setIf(final boolean condition)
- {
- getStateHelper().put(PropertyKeys.ifAttr, condition);
- }
-
- // ----------------------------------------------------- UIComponent Methods
- /**
- * <p>
- * In addition to to the default {@link UIComponent#broadcast} processing,
- * pass the {@link ActionEvent} being broadcast to the default
- * {@link ActionListener} registered on the
- * {@link javax.faces.application.Application}.
- * </p>
- *
- * @param event {@link FacesEvent} to be broadcast
- *
- * @throws AbortProcessingException Signal the JavaServer Faces
- * implementation that no further processing on the current event
- * should be performed
- * @throws IllegalArgumentException if the implementation class of this
- * {@link FacesEvent} is not supported by this component
- * @throws NullPointerException if <code>event</code> is <code>null</code>
- */
- @Override
- public void broadcast(final FacesEvent event) throws AbortProcessingException
- {
-
- super.broadcast(event);
-
- FacesContext context = getFacesContext();
-
- // OPEN QUESTION: should we consider a navigation to the same view as a
- // no-op navigation?
-
- // only proceed if the response has not been marked complete and
- // navigation to another view has not occurred
- if ((event instanceof ActionEvent) && !context.getResponseComplete() && (context.getViewRoot() == getViewRootOf(event)))
- {
- ActionListener listener = context.getApplication().getActionListener();
- if (listener != null)
- {
- UIViewRoot viewRootBefore = context.getViewRoot();
- InstrumentedFacesContext instrumentedContext = new InstrumentedFacesContext(context);
- // defer the call to renderResponse() that happens in
- // ActionListener#processAction(ActionEvent)
- instrumentedContext.disableRenderResponseControl().set();
- listener.processAction((ActionEvent) event);
- instrumentedContext.restore();
- // if the response is marked complete, the story is over
- if (!context.getResponseComplete())
- {
- UIViewRoot viewRootAfter = context.getViewRoot();
- // if the view id changed as a result of navigation, then execute
- // the JSF lifecycle for the new view id
- if (viewRootBefore != viewRootAfter)
- {
- /*
- * // execute the JSF lifecycle by dispatching a forward
- * request // this approach is problematic because it throws a
- * wrench in the event broadcasting try {
- * context.getExternalContext
- * ().dispatch(context.getApplication()
- * .getViewHandler().getActionURL(context,
- * viewRootAfter.getViewId())
- * .substring(context.getExternalContext
- * ().getRequestContextPath().length())); // kill this
- * lifecycle execution context.responseComplete(); } catch
- * (IOException e) { throw new
- * FacesException("Dispatch to viewId failed: " +
- * viewRootAfter.getViewId(), e); }
- */
-
- // manually execute the JSF lifecycle on the new view id
- // certain tweaks have to be made to the FacesContext to allow
- // us to reset the lifecycle
- Lifecycle lifecycle = getLifecycle(context);
- instrumentedContext = new InstrumentedFacesContext(context);
- instrumentedContext.pushViewIntoRequestMap().clearViewRoot().clearPostback().set();
- lifecycle.execute(instrumentedContext);
- instrumentedContext.restore();
-
- /*
- * Another approach would be to register a phase listener in
- * the decode() method for the phase in which the action is
- * set to invoke. The phase listener would performs a servlet
- * forward if a non-redirect navigation occurs after the
- * phase.
- */
- }
- else
- {
- // apply the deferred call (relevant when immediate is true)
- context.renderResponse();
- }
- }
- }
- }
- }
-
- /**
- * First, determine if the action should be invoked by evaluating this
- * components pre-conditions. If this is a faces (postback) request and the
- * evaluated value of the postback attribute is false, take no action. If the
- * evaluated value of the if attribute is false, take no action. If both
- * conditions pass, proceed with creating an {@link ActionEvent}.
- *
- * Set the phaseId in which the queued {@link ActionEvent} should be
- * broadcast by assigning the appropriate value to the phaseId property of
- * the {@link ActionEvent} according to the evaluated value of the immediate
- * attribute. If the value is <literal>true</literal>, set the phaseId to
- * {@link PhaseId#APPLY_REQUEST_VALUES}. Otherwise, set the phaseId to to
- * {@link PhaseId#INVOKE_APPLICATION}.
- *
- * Finally, queue the event by calling <literal>queueEvent()</literal> and
- * passing the {@link ActionEvent} just created.
- */
- @Override
- public void decode(final FacesContext context)
- {
- if (context == null)
- {
- throw new NullPointerException();
- }
-
- if ((context.isPostback() && !isOnPostback()) || !isIf())
- {
- return;
- }
-
- ActionEvent e = new ActionEvent(this);
- PhaseId phaseId = getPhaseId();
- if (phaseId != null)
- {
- e.setPhaseId(phaseId);
- }
- else if (isImmediate())
- {
- e.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
- }
- else
- {
- e.setPhaseId(PhaseId.INVOKE_APPLICATION);
- }
-
- queueEvent(e);
- }
-
- private UIViewRoot getViewRootOf(final FacesEvent e)
- {
- UIComponent c = e.getComponent();
- do
- {
- if (c instanceof UIViewRoot)
- {
- return (UIViewRoot) c;
- }
- c = c.getParent();
- }
- while (c != null);
- return null;
- }
-
- private Lifecycle getLifecycle(final FacesContext context)
- {
- LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
- String lifecycleId = context.getExternalContext().getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
- if (lifecycleId == null)
- {
- lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
- }
- return lifecycleFactory.getLifecycle(lifecycleId);
- }
-
- /**
- * A FacesContext delegator that gives us the necessary controls over the
- * FacesContext to allow the execution of the lifecycle to accomodate the
- * UIViewAction sequence.
- */
- private class InstrumentedFacesContext extends FacesContextWrapper
- {
-
- private final FacesContext wrapped;
- private boolean viewRootCleared = false;
- private boolean renderedResponseControlDisabled = false;
- private Boolean postback = null;
-
- public InstrumentedFacesContext(final FacesContext wrapped)
- {
- this.wrapped = wrapped;
- }
-
- @Override
- public FacesContext getWrapped()
- {
- return wrapped;
- }
-
- @Override
- public UIViewRoot getViewRoot()
- {
- if (viewRootCleared)
- {
- return null;
- }
-
- return wrapped.getViewRoot();
- }
-
- @Override
- public void setViewRoot(final UIViewRoot viewRoot)
- {
- viewRootCleared = false;
- wrapped.setViewRoot(viewRoot);
- }
-
- @Override
- public boolean isPostback()
- {
- return postback == null ? wrapped.isPostback() : postback;
- }
-
- @Override
- public void renderResponse()
- {
- if (!renderedResponseControlDisabled)
- {
- wrapped.renderResponse();
- }
- }
-
- /**
- * Make it look like we have dispatched a request using the include
- * method.
- */
- public InstrumentedFacesContext pushViewIntoRequestMap()
- {
- getExternalContext().getRequestMap().put("javax.servlet.include.servlet_path", wrapped.getViewRoot().getViewId());
- return this;
- }
-
- public InstrumentedFacesContext clearPostback()
- {
- postback = false;
- return this;
- }
-
- public InstrumentedFacesContext clearViewRoot()
- {
- viewRootCleared = true;
- return this;
- }
-
- public InstrumentedFacesContext disableRenderResponseControl()
- {
- renderedResponseControlDisabled = true;
- return this;
- }
-
- public void set()
- {
- setCurrentInstance(this);
- }
-
- public void restore()
- {
- setCurrentInstance(wrapped);
- }
- }
-}
Modified: modules/faces/trunk/pom.xml
===================================================================
--- modules/faces/trunk/pom.xml 2010-05-28 20:39:48 UTC (rev 12895)
+++ modules/faces/trunk/pom.xml 2010-05-28 23:06:51 UTC (rev 12896)
@@ -102,6 +102,11 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>javax.validation</groupId>
+ <artifactId>validation-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-extensions</artifactId>
<version>${weldx.version}</version>
More information about the seam-commits
mailing list