- JavaDoc improvements across the whole of Spring Faces.

- General polishing of the ui package.
This commit is contained in:
Jeremy Grelle
2008-04-24 00:20:51 +00:00
parent 17e831d03e
commit f465b65e6c
63 changed files with 396 additions and 186 deletions

View File

@@ -28,5 +28,6 @@
<classpathentry kind="var" path="IVY_CACHE/javax.faces/jsf-api/jsf-api-1.2.08.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.faces/jsf-impl/jsf-impl-1.2.08.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/spring-js"/>
<classpathentry kind="var" path="IVY_CACHE/com.sun.facelets/jsf-facelets/jsf-facelets-1.1.14.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -19,6 +19,7 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* Namespace handler for the faces namespace.
*
* @author Jeremy Grelle
*/
public class FacesConfigNamespaceHandler extends NamespaceHandlerSupport {

View File

@@ -30,6 +30,8 @@ import org.w3c.dom.Element;
/**
* Parser for the flow-builder-services tag.
*
* @author Jeremy Grelle
*/
public class FacesFlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefinitionParser implements
BeanDefinitionParser {

View File

@@ -0,0 +1,5 @@
<html>
<body>
<p>Configuration support for the Spring Faces custom XML namespace.</p>
</body>
</html>

View File

@@ -21,6 +21,11 @@ import javax.faces.el.EvaluationException;
import javax.faces.el.PropertyNotFoundException;
import javax.faces.el.PropertyResolver;
/**
* A JSF 1.1 {@link PropertyResolver} that delegates to a wrapped Unified EL resolver chain for property resolution.
*
* @author Jeremy Grelle
*/
public abstract class ELDelegatingPropertyResolver extends PropertyResolver {
private PropertyResolver nextResolver;

View File

@@ -21,6 +21,11 @@ import javax.faces.context.FacesContext;
import javax.faces.el.EvaluationException;
import javax.faces.el.VariableResolver;
/**
* A JSF 1.1 {@link VariableResolver} that delegates to a wrapped Unified EL resolver chain for variable resolution.
*
* @author Jeremy Grelle
*/
public abstract class ELDelegatingVariableResolver extends VariableResolver {
private VariableResolver nextResolver;

View File

@@ -20,6 +20,11 @@ import javax.el.ELResolver;
import javax.el.FunctionMapper;
import javax.el.VariableMapper;
/**
* A minimal {@link ELContext} implementation.
*
* @author Jeremy Grelle
*/
class SimpleELContext extends ELContext {
private ELResolver resolver;

View File

@@ -0,0 +1,5 @@
<html>
<body>
<p>Support for adapting Unified EL resolvers to the JSF 1.1 API.</p>
</body>
</html>

View File

@@ -29,6 +29,9 @@ import org.springframework.util.Assert;
*/
public class OneSelectionTrackingListDataModel extends SerializableListDataModel implements SelectionAware {
/**
* The list of currently selected row data objects.
*/
private List selections = new ArrayList();
public OneSelectionTrackingListDataModel() {

View File

@@ -26,15 +26,38 @@ import javax.faces.model.DataModel;
*/
public interface SelectionAware {
/**
* Checks whether the row pointed to by the model's current index is selected.
* @return true if the current row data object is selected
*/
public boolean isCurrentRowSelected();
/**
* Sets whether the row pointed to by the model's current index is selected
* @param rowSelected true to select the current row
*/
public void setSelected(boolean rowSelected);
/**
* Sets the list of selected row data objects for the model.
* @param selections the list of selected row data objects
*/
public void setSelections(List selections);
/**
* Returns the list of selected row data objects for the model.
* @return the list of selected row data objects
*/
public List getSelections();
/**
* Selects all row data objects in the model.
*/
public void selectAll();
/**
* Selects the given row data object in the model.
* @param rowData the row data object to select.
*/
public void select(Object rowData);
}

View File

@@ -27,6 +27,8 @@ import org.springframework.util.Assert;
/**
* A simple List-to-JSF-DataModel adapter that is also serializable.
*
* @author Jeremy Grelle
*/
public class SerializableListDataModel extends DataModel implements Serializable {

View File

@@ -20,9 +20,16 @@ import java.util.List;
import javax.faces.model.DataModel;
import org.springframework.binding.convert.Converter;
import org.springframework.binding.convert.converters.AbstractConverter;
import org.springframework.util.ClassUtils;
/**
* A {@link Converter} implementation that converts an Object, Object array, or {@link List} into a JSF
* {@link DataModel}.
*
* @author Jeremy Grelle
*/
public class DataModelConverter extends AbstractConverter {
protected Object doConvert(Object source, Class targetClass, Object context) throws Exception {

View File

@@ -21,6 +21,11 @@ import org.springframework.faces.model.OneSelectionTrackingListDataModel;
* Convenient {@link ConversionService} implementation for JSF that composes JSF-specific converters with the standard
* Web Flow converters.
*
* <p>
* In addition to the standard Web Flow conversion, this service provide conversion from a {@link List} into a
* {@link OneSelectionTrackingListDataModel} using a "dataModel" alias for the type.
* </p>
*
* @author Jeremy Grelle
*/
public class FacesConversionService extends DefaultConversionService {

View File

@@ -0,0 +1,5 @@
<html>
<body>
<p>Conversion support for JSF-specific data structures.</p>
</body>
</html>

View File

@@ -0,0 +1,5 @@
<html>
<body>
<p>Extended implementations of JSF-specific data structures such as DataModel.</p>
</body>
</html>

View File

@@ -0,0 +1,5 @@
<html>
<body>
<p>Support for JSF integration with Spring MVC.</p>
</body>
</html>

View File

@@ -0,0 +1,5 @@
<html>
<body>
<p>Ajax integration support for the Rich Faces component library.</p>
</body>
</html>

View File

@@ -0,0 +1,5 @@
<html>
<body>
<p>Development and debugging support for working with JSF.</p>
</body>
</html>

View File

@@ -1,22 +0,0 @@
/*
* Copyright 2004-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.faces.ui;
import javax.faces.component.UICommand;
public class AjaxEventInterceptor extends UICommand {
}

View File

@@ -26,7 +26,13 @@ import javax.faces.event.ActionEvent;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
public class AjaxEventInterceptorRenderer extends DojoRenderer {
/**
* {@link Renderer} for the {@code <sf:ajaxEvent>} tag.
*
* @author Jeremy Grelle
*
*/
public class AjaxEventInterceptorRenderer extends DojoDecorationRenderer {
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
String event = (String) component.getAttributes().get("event");
@@ -59,7 +65,7 @@ public class AjaxEventInterceptorRenderer extends DojoRenderer {
private String getElementId(FacesContext context, UIComponent component) {
if (component.getChildCount() > 0) {
UIComponent child = (UIComponent) component.getChildren().get(0);
if (!(child instanceof DojoAdvisor)) {
if (!(child instanceof DojoDecoration)) {
return child.getClientId(context);
} else {
return getElementId(context, child);

View File

@@ -32,6 +32,7 @@ import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import javax.faces.lifecycle.Lifecycle;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -40,6 +41,12 @@ import org.springframework.webflow.execution.View;
/**
* Customizes the behavior of an existing UIViewRoot with Ajax-aware processing.
*
* <p>
* This component is the key to rendering partial subtrees of the JSF component tree. It makes use of JSF 1.2's
* {@link UIComponent#invokeOnComponent(FacesContext, String, ContextCallback)} method to execute the various phases of
* the {@link Lifecycle} on each subtree.
* </p>
*
* @author Jeremy Grelle
*/
public class AjaxViewRoot extends DelegatingViewRoot {

View File

@@ -23,7 +23,13 @@ import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
public abstract class BaseParentComponentRenderer extends BaseHtmlParentTagRenderer {
/**
* Base {@link Renderer} for typical faces components, handling the rendering for common {@link UIComponent} attributes.
*
* @author Jeremy Grelle
*
*/
public abstract class BaseComponentRenderer extends BaseHtmlTagRenderer {
private Map attributeCallbacks;

View File

@@ -22,7 +22,14 @@ import javax.faces.context.FacesContext;
import org.springframework.faces.ui.resource.ResourceHelper;
public abstract class BaseDojoParentComponentRenderer extends BaseSpringFacesParentComponentRenderer {
/**
* Base {@link Renderer} for components that require the Dojo implementation of Spring JavaScript to be available on the
* client.
*
* @author Jeremy Grelle
*
*/
public abstract class BaseDojoComponentRenderer extends BaseSpringJavascriptComponentRenderer {
private String dojoJsResourceUri = "/dojo/dojo.js";

View File

@@ -27,9 +27,19 @@ import javax.faces.render.Renderer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
abstract class BaseHtmlParentTagRenderer extends Renderer {
/**
* Abstract base {@link Renderer} for a component that renders a standard HTML element.
*
* <p>
* Uses a callback mechanism for customizing the rendering of tag attributes when logic is required beyond a simple
* pass-through of the component attribute to the HTML attribute of the rendered element.
* </p>
*
* @author Jeremy Grelle
*/
abstract class BaseHtmlTagRenderer extends Renderer {
protected Log log = LogFactory.getLog(BaseHtmlParentTagRenderer.class);
protected Log log = LogFactory.getLog(BaseHtmlTagRenderer.class);
/**
* Default {@link RenderAttributeCallback} that just renders the tag attribute as a pass-through value if the value

View File

@@ -22,7 +22,13 @@ import javax.faces.context.FacesContext;
import org.springframework.faces.ui.resource.ResourceHelper;
public abstract class BaseSpringFacesParentComponentRenderer extends BaseParentComponentRenderer {
/**
* Base {@link Renderer} for components that require the Spring JavaScript library on the client.
*
* @author Jeremy Grelle
*
*/
public abstract class BaseSpringJavascriptComponentRenderer extends BaseComponentRenderer {
private String springJsResourceUri = "/spring/Spring.js";

View File

@@ -23,7 +23,7 @@ import javax.faces.render.Renderer;
import org.springframework.faces.ui.resource.ResourceHelper;
public class SpringFacesRenderer extends Renderer {
public abstract class BaseSpringJavascriptDecorationRenderer extends Renderer {
private String springJsResourceUri = "/spring/Spring.js";

View File

@@ -18,7 +18,14 @@ package org.springframework.faces.ui;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
public class DojoClientCurrencyValidator extends DojoAdvisor {
/**
* Component that uses the Dojo implementation of Spring JavaScript to decorate a child input component with client-side
* currency validation behavior.
*
* @author Jeremy Grelle
*
*/
public class DojoClientCurrencyValidator extends DojoDecoration {
private static final String DOJO_COMPONENT_TYPE = "dijit.form.CurrencyTextBox";
@@ -27,9 +34,9 @@ public class DojoClientCurrencyValidator extends DojoAdvisor {
private static final String[] DOJO_ATTRS;
static {
DOJO_ATTRS = new String[DojoAdvisor.DOJO_ATTRS.length + DOJO_ATTRS_INTERNAL.length];
System.arraycopy(DojoAdvisor.DOJO_ATTRS, 0, DOJO_ATTRS, 0, DojoAdvisor.DOJO_ATTRS.length);
System.arraycopy(DOJO_ATTRS_INTERNAL, 0, DOJO_ATTRS, DojoAdvisor.DOJO_ATTRS.length, DOJO_ATTRS_INTERNAL.length);
DOJO_ATTRS = new String[DojoDecoration.DOJO_ATTRS.length + DOJO_ATTRS_INTERNAL.length];
System.arraycopy(DojoDecoration.DOJO_ATTRS, 0, DOJO_ATTRS, 0, DojoDecoration.DOJO_ATTRS.length);
System.arraycopy(DOJO_ATTRS_INTERNAL, 0, DOJO_ATTRS, DojoDecoration.DOJO_ATTRS.length, DOJO_ATTRS_INTERNAL.length);
}
private String currency;

View File

@@ -15,12 +15,19 @@
*/
package org.springframework.faces.ui;
public class DojoClientDateValidator extends DojoAdvisor {
/**
* Component that uses the Dojo implementation of Spring JavaScript to decorate a child input component with client-side
* date validation behavior.
*
* @author Jeremy Grelle
*
*/
public class DojoClientDateValidator extends DojoDecoration {
private static final String DOJO_COMPONENT_TYPE = "dijit.form.DateTextBox";
protected String[] getDojoAttributes() {
return DojoAdvisor.DOJO_ATTRS;
return DojoDecoration.DOJO_ATTRS;
}
public String getDojoComponentType() {

View File

@@ -15,12 +15,19 @@
*/
package org.springframework.faces.ui;
public class DojoClientNumberValidator extends DojoAdvisor {
/**
* Component that uses the Dojo implementation of Spring JavaScript to decorate a child input component with client-side
* numeric validation behavior.
*
* @author Jeremy Grelle
*
*/
public class DojoClientNumberValidator extends DojoDecoration {
private static final String DOJO_COMPONENT_TYPE = "dijit.form.NumberTextBox";
protected String[] getDojoAttributes() {
return DojoAdvisor.DOJO_ATTRS;
return DojoDecoration.DOJO_ATTRS;
}
public String getDojoComponentType() {

View File

@@ -15,12 +15,19 @@
*/
package org.springframework.faces.ui;
public class DojoClientTextValidator extends DojoAdvisor {
/**
* Component that uses the Dojo implementation of Spring JavaScript to decorate a child input component with client-side
* text validation behavior.
*
* @author Jeremy Grelle
*
*/
public class DojoClientTextValidator extends DojoDecoration {
private static final String DOJO_COMPONENT_TYPE = "dijit.form.ValidationTextBox";
protected String[] getDojoAttributes() {
return DojoAdvisor.DOJO_ATTRS;
return DojoDecoration.DOJO_ATTRS;
}
public String getDojoComponentType() {

View File

@@ -15,11 +15,19 @@
*/
package org.springframework.faces.ui;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
public abstract class DojoAdvisor extends UIComponentBase {
/**
* Base {@link UIComponent} for a component that uses the Dojo implementation of Spring JavaScript to decorate a child
* component with enhanced client-side behavior.
*
* @author Jeremy Grelle
*
*/
public abstract class DojoDecoration extends UIComponentBase {
protected static final String[] DOJO_ATTRS = new String[] { "disabled", "intermediateChanges", "tabIndex",
"required", "promptMessage", "invalidMessage", "constraints", "regExp", "regExpGen" };
@@ -161,7 +169,7 @@ public abstract class DojoAdvisor extends UIComponentBase {
public String getFamily() {
return "spring.faces.Advisor";
return "spring.faces.Decoration";
}
}

View File

@@ -27,12 +27,38 @@ import javax.faces.context.ResponseWriter;
import org.springframework.faces.ui.resource.ResourceHelper;
import org.springframework.util.StringUtils;
public class DojoAdvisorRenderer extends DojoRenderer {
/**
* Generic renderer for components that use the Dojo implementation of Spring JavaScript to decorate a child component
* with enhanced client-side behavior.
*
* @author Jeremy Grelle
*
*/
public class DojoDecorationRenderer extends BaseSpringJavascriptDecorationRenderer {
private static final String SCRIPT_ELEMENT = "script";
private String dojoJsResourceUri = "/dojo/dojo.js";
private String dijitThemePath = "/dijit/themes/";
private String dijitTheme = "tundra";
private String springDojoJsResourceUri = "/spring/Spring-Dojo.js";
private ResourceHelper resourceHelper = new ResourceHelper();
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
super.encodeBegin(context, component);
resourceHelper.renderStyleLink(context, dijitThemePath + dijitTheme + "/" + dijitTheme + ".css");
resourceHelper.renderScriptLink(context, dojoJsResourceUri);
resourceHelper.renderScriptLink(context, springDojoJsResourceUri);
}
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
ResponseWriter writer = context.getResponseWriter();
@@ -42,14 +68,14 @@ public class DojoAdvisorRenderer extends DojoRenderer {
UIComponent advisedChild = (UIComponent) component.getChildren().get(0);
resourceHelper.renderDojoInclude(context, ((DojoAdvisor) component).getDojoComponentType());
resourceHelper.renderDojoInclude(context, ((DojoDecoration) component).getDojoComponentType());
writer.startElement(SCRIPT_ELEMENT, component);
writer.writeAttribute("type", "text/javascript", null);
StringBuffer script = new StringBuffer();
script.append(" Spring.addDecoration(new Spring.ElementDecoration({ ");
script.append(" elementId : '" + advisedChild.getClientId(context) + "', ");
script.append(" widgetType : '" + ((DojoAdvisor) component).getDojoComponentType() + "', ");
script.append(" widgetType : '" + ((DojoDecoration) component).getDojoComponentType() + "', ");
script.append(" widgetAttrs : { ");
String nodeAttrs = getNodeAttributesAsString(context, advisedChild);
@@ -96,7 +122,7 @@ public class DojoAdvisorRenderer extends DojoRenderer {
protected String getDojoAttributesAsString(FacesContext context, UIComponent component) {
DojoAdvisor advisor = (DojoAdvisor) component;
DojoDecoration advisor = (DojoDecoration) component;
StringBuffer attrs = new StringBuffer();
for (int i = 0; i < advisor.getDojoAttributes().length; i++) {

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2004-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.faces.ui;
import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.springframework.faces.ui.resource.ResourceHelper;
public class DojoRenderer extends SpringFacesRenderer {
private String dojoJsResourceUri = "/dojo/dojo.js";
private String dijitThemePath = "/dijit/themes/";
private String dijitTheme = "tundra";
private String springDojoJsResourceUri = "/spring/Spring-Dojo.js";
private ResourceHelper resourceHelper = new ResourceHelper();
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
super.encodeBegin(context, component);
resourceHelper.renderStyleLink(context, dijitThemePath + dijitTheme + "/" + dijitTheme + ".css");
resourceHelper.renderScriptLink(context, dojoJsResourceUri);
resourceHelper.renderScriptLink(context, springDojoJsResourceUri);
}
}

View File

@@ -23,6 +23,12 @@ import javax.faces.render.Renderer;
import org.springframework.faces.ui.resource.ResourceHelper;
/**
* {@link Renderer} implementation that renders the CSS resources required by Dojo's widget system.
*
* @author Jeremy Grelle
*
*/
public class DojoStyleRenderer extends Renderer {
private static final String dijitThemePath = "/dijit/themes/";

View File

@@ -15,8 +15,16 @@
*/
package org.springframework.faces.ui;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
/**
* A completely dynamic component that is used to back simple Facelets tags. Relies solely on the use of
* {@link UIComponent#getAttributes()} instead of JavaBean style getters and setters.
*
* @author Jeremy Grelle
*
*/
public class DynamicComponent extends UIComponentBase {
public String getFamily() {

View File

@@ -18,6 +18,11 @@ package org.springframework.faces.ui;
import java.util.HashMap;
import java.util.Map;
/**
* Helper class that provides common attributes for standard HTML elements.
*
* @author Jeremy Grelle
*/
final class HTML {
/**

View File

@@ -32,7 +32,13 @@ import javax.faces.event.ActionEvent;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
public class ProgressiveCommandButtonRenderer extends BaseDojoParentComponentRenderer {
/**
* {@link Renderer} for the {@code <sf:commandButton>} tag.
*
* @author Jeremy Grelle
*
*/
public class ProgressiveCommandButtonRenderer extends BaseDojoComponentRenderer {
private static String[] ATTRIBUTES_TO_RENDER;
@@ -101,7 +107,7 @@ public class ProgressiveCommandButtonRenderer extends BaseDojoParentComponentRen
/**
* This is a hook for subclasses to provide special onclick behavior in the non-ajax case
* @return
* @return the onclick value to use when Ajax is disabled.
*/
protected String getOnClickNoAjax(FacesContext context, UIComponent component) {
// No special behavior necessary for CommandButton

View File

@@ -1,24 +0,0 @@
/*
* Copyright 2004-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.faces.ui;
public class ProgressiveCommandLink extends ProgressiveCommandButton {
public String getRendererType() {
return "spring.faces.ProgressiveCommandLink";
}
}

View File

@@ -32,6 +32,17 @@ import javax.faces.context.ResponseWriter;
import org.springframework.beans.BeanUtils;
import org.springframework.faces.webflow.JsfUtils;
/**
* {@link Renderer} for the {@code <sf:commandLink>} tag.
*
* <p>
* This renderer is unique in that it first renders a button that will still work if JavaScript is disabled on the
* client, then progressively enhances the button and transforms it into a link if JavaScript is available.
* </p>
*
* @author Jeremy Grelle
*
*/
public class ProgressiveCommandLinkRenderer extends ProgressiveCommandButtonRenderer {
private static String[] ATTRIBUTES_TO_RENDER;
@@ -78,9 +89,10 @@ public class ProgressiveCommandLinkRenderer extends ProgressiveCommandButtonRend
// No need to be progressive if this is an AJAX request since it can be assumed JavaScript is enabled
if (!JsfUtils.isAsynchronousFlowRequest()) {
// Render a plain submit button first if this is not an ajax request
ProgressiveCommandButton button = new ProgressiveCommandButton();
ProgressiveUICommand button = new ProgressiveUICommand();
button.getAttributes().putAll(component.getAttributes());
BeanUtils.copyProperties(component, button);
button.setRendererType("spring.faces.ProgressiveCommandButtonRenderer");
button.setAjaxEnabled(Boolean.FALSE);
button.encodeBegin(context);
button.encodeChildren(context);

View File

@@ -16,6 +16,7 @@
package org.springframework.faces.ui;
import javax.faces.component.UICommand;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
@@ -24,14 +25,18 @@ import org.springframework.webflow.engine.TransitionableState;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.RequestContextHolder;
public class ProgressiveCommandButton extends UICommand {
/**
* {@link UIComponent} implementation that backs the {@code <sf:commandButton>} tag. Relies mainly on the use of
* {@link UIComponent#getAttributes()} as opposed to JavaBean getters and setters, except for attribute that require
* type conversion.
*
* @author Jeremy Grelle
*
*/
public class ProgressiveUICommand extends UICommand {
private String type = "submit";
public String getRendererType() {
return "spring.faces.ProgressiveCommandButton";
}
private Boolean disabled;
private Boolean ajaxEnabled = Boolean.TRUE;

View File

@@ -21,7 +21,13 @@ import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
public interface RenderAttributeCallback {
/**
* Callback interface used to provide custom behavior for the rendering of a particular component attribute.
*
* @author Jeremy Grelle
*
*/
interface RenderAttributeCallback {
public void doRender(FacesContext context, ResponseWriter writer, UIComponent component, String attribute,
Object attributeValue, String property) throws IOException;

View File

@@ -21,7 +21,13 @@ import javax.faces.component.UIForm;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
public class RendererUtils {
/**
* Helper class for common renderer functionality.
*
* @author Jeremy Grelle
*
*/
class RendererUtils {
public static String getFormId(FacesContext context, UIComponent component) {
if (component.getParent() instanceof UIForm) {

View File

@@ -23,6 +23,18 @@ import javax.faces.render.Renderer;
import org.springframework.faces.ui.resource.ResourceHelper;
/**
* {@link Renderer} for the {@code <sf:resourceGroup>} tag.
*
* <p>
* This render outputs a specially formatted Javascript or CSS include that requests multiple resources with one HTTP
* request.
* </p>
*
* @author Jeremy Grelle
*
* TODO - Make this work with Javacript resources
*/
public class ResourceGroupRenderer extends Renderer {
private static final ResourceHelper resourceHelper = new ResourceHelper();

View File

@@ -22,8 +22,19 @@ import javax.faces.context.FacesContext;
import javax.faces.render.Renderer;
import org.springframework.faces.ui.resource.ResourceHelper;
import org.springframework.js.resource.ResourceServlet;
import org.springframework.util.Assert;
/**
* {@link Renderer} for the {@code <sf:resource>} tag.
*
* <p>
* Renders a Javascript or CSS include with a URL properly formatted to map to the {@link ResourceServlet}.
* </p>
*
* @author Jeremy Grelle
*
*/
public class ResourceRenderer extends Renderer {
private static final ResourceHelper resourceHelper = new ResourceHelper();

View File

@@ -1,26 +0,0 @@
/*
* Copyright 2004-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.faces.ui;
import javax.faces.component.UIComponentBase;
public class ValidateAll extends UIComponentBase {
public String getFamily() {
return "spring.faces.Advisor";
}
}

View File

@@ -23,7 +23,13 @@ import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
public class ValidateAllRenderer extends SpringFacesRenderer {
/**
* {@link Renderer} for the {@code <sf:validateAllOnClick>} tag.
*
* @author Jeremy Grelle
*
*/
public class ValidateAllRenderer extends BaseSpringJavascriptDecorationRenderer {
private static final String SCRIPT_ELEMENT = "script";

View File

@@ -0,0 +1,5 @@
<html>
<body>
<p>Spring Faces component library.</p>
</body>
</html>

View File

@@ -27,11 +27,13 @@ import java.util.Set;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import org.springframework.js.resource.ResourceServlet;
/**
* Helper used by Spring Faces component renderers to add links to javascript and css resources. The resource links will
* be rendered in the correct format for the requests to be handled by Web Flow and routed to a special "resources" flow
* that is engineered at runtime. The resource paths are cached so that a particular resource link is only rendered once
* per request.
* be rendered in the correct format for the requests to be handled by the Spring JavaScript {@link ResourceServlet}.
* The resource paths are cached so that a particular resource link is only rendered once per request.
*
* @author Jeremy Grelle
*
*/

View File

@@ -0,0 +1,5 @@
<html>
<body>
<p>Support for providing JavaScript, CSS, and image resources needed by Spring Faces components.</p>
</body>
</html>

View File

@@ -43,12 +43,16 @@ import org.springframework.webflow.mvc.view.MessageContextErrors;
/**
* The default {@link ActionListener} implementation to be used with Web Flow.
*
* <p>
* This implementation bypasses the JSF {@link NavigationHandler} mechanism to instead let the event be handled directly
* by Web Flow.
* </p>
*
* <p>
* Web Flow's model-level validation will be invoked here after an event has been detected if the event is not an
* immediate event.
* </p>
*
* @author Jeremy Grelle
*/

View File

@@ -17,7 +17,15 @@ package org.springframework.faces.webflow;
import javax.faces.application.Application;
import javax.faces.application.ApplicationFactory;
import javax.faces.application.StateManager;
/**
* Custom {@link ApplicationFactory} that ensures the FlowViewStateManager is the first {@link StateManager} in the
* chain so that Web Flow may manage JSF component state when a flow is active.
*
* @author Jeremy Grelle
*
*/
public class FlowApplicationFactory extends ApplicationFactory {
private ApplicationFactory delegate;

View File

@@ -41,7 +41,9 @@ import org.springframework.webflow.execution.RequestContext;
/**
* Custom {@link FacesContext} implementation that delegates all standard FacesContext messaging functionality to a
* Spring {@link MessageSource} made accessible as part of the current Web Flow request.
* Spring {@link MessageSource} made accessible as part of the current Web Flow request. Additionally, it manages the
* {@code responseComplete} and {@code renderResponse} flags in flash scope so that the execution of the JSF
* {@link Lifecycle} may span multiple requests in the case of the POST+REDIRECT+GET pattern being enabled.
*
* @author Jeremy Grelle
*/

View File

@@ -34,6 +34,7 @@ import org.apache.commons.logging.LogFactory;
* <p>
* This Lifecycle does not execute the RESTORE_VIEW phase since view creation and restoration are now handled by the
* {@link JsfViewFactory}.
* </p>
*
* @author Jeremy Grelle
*/

View File

@@ -18,13 +18,20 @@ package org.springframework.faces.webflow;
import javax.el.CompositeELResolver;
import javax.faces.el.PropertyResolver;
import org.springframework.binding.collection.MapAdaptable;
import org.springframework.binding.expression.el.MapAdaptableELResolver;
import org.springframework.context.MessageSource;
import org.springframework.faces.expression.ELDelegatingPropertyResolver;
import org.springframework.webflow.expression.el.FlowResourceELResolver;
/**
* For resolving MapAdaptable properties with JSF 1.1 or >.
* Custom property resolver for resolving properties on web flow specific structures with JSF 1.1 or > by delegating to
* web flow's EL resolvers.
*
* <p>
* This resolver handles resolving properties on a {@link MapAdaptable} collection and a flow-local
* {@link MessageSource}
* </p>
* @author Jeremy Grelle
*/
public class FlowPropertyResolver extends ELDelegatingPropertyResolver {

View File

@@ -25,7 +25,8 @@ import org.springframework.webflow.expression.el.RequestContextELResolver;
import org.springframework.webflow.expression.el.ScopeSearchingELResolver;
/**
* For resolving flow request context variables with JSF 1.1 or >.
* Custom variabe resolver for resolving properties on web flow specific variables with JSF 1.1 or > by delegating to
* web flow's EL resolvers.
*
* @author Jeremy Grelle
*/

View File

@@ -28,6 +28,11 @@ import org.springframework.core.style.ToStringCreator;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.RequestContextHolder;
/**
* Custom {@link StateManager} that manages the JSF component state in web flow's view scope.
*
* @author Jeremy Grelle
*/
public class FlowViewStateManager extends StateManager {
private static final Log logger = LogFactory.getLog(FlowViewStateManager.class);

View File

@@ -36,7 +36,7 @@ import org.springframework.webflow.expression.el.ScopeSearchingELResolver;
import org.springframework.webflow.expression.el.SpringBeanWebFlowELResolver;
/**
* A JSF-specific ExpressionParser that allows beans managed by either JSF, Spring, or Web Flow referenced in
* A JSF-specific ExpressionParser that allows beans managed by either JSF, Spring, or Web Flow to be referenced in
* expressions in the FlowDefinition.
*
* @author Jeremy Grelle

View File

@@ -75,7 +75,7 @@ public class JsfView implements View {
}
/**
* This implementation performs the standard duties of the JSF RENDER_RESPONSE phase.
* Performs the standard duties of the JSF RENDER_RESPONSE phase.
*/
public void render() throws IOException {
FacesContext facesContext = FlowFacesContext.newInstance(requestContext, facesLifecycle);
@@ -93,6 +93,10 @@ public class JsfView implements View {
}
}
/**
* Executes postback-processing portions of the standard JSF lifecyle including APPLY_REQUEST_VALUES through
* INVOKE_APPLICATION.
*/
public void processUserEvent() {
FacesContext facesContext = FlowFacesContext.newInstance(requestContext, facesLifecycle);
facesContext.setViewRoot(viewRoot);

View File

@@ -45,9 +45,8 @@ import org.springframework.webflow.execution.ViewFactory;
/**
* JSF-specific {@link ViewFactory} implementation.
* <p>
* This factory is responsible for performing the duties of the RESTORE_VIEW phase of the JSF lifecycle. If the current
* request is a post-back, then the rest of the standard JSF lifecyle through INVOKE_APPLICATION will be executed as
* well when an existing {@link JsfView} is found and restored.
* This factory is responsible for performing the duties of the RESTORE_VIEW phase of the JSF lifecycle.
* </p>
*
* @author Jeremy Grelle
*/
@@ -64,6 +63,10 @@ public class JsfViewFactory implements ViewFactory {
this.lifecycle = lifecycle;
}
/**
* Executes the RESTORE_VIEW phase of the JSF lifecycle at the beginning of a request, and creates the next view to
* be rendered in the case of an executing transition.
*/
public View getView(RequestContext context) {
FacesContext facesContext = FlowFacesContext.newInstance(context, lifecycle);
try {

View File

@@ -26,6 +26,7 @@ import org.springframework.webflow.execution.RequestContextHolder;
/**
* JSF 1.1 variable resolver for Spring Beans accessible to the flow's local bean factory.
*
* @author Jeremy Grelle
*/
public class SpringBeanWebFlowVariableResolver extends SpringBeanVariableResolver {

View File

@@ -24,17 +24,17 @@
<component>
<component-type>spring.faces.ProgressiveCommandButton</component-type>
<component-class>org.springframework.faces.ui.ProgressiveCommandButton</component-class>
<component-class>org.springframework.faces.ui.ProgressiveUICommand</component-class>
</component>
<component>
<component-type>spring.faces.ProgressiveCommandLink</component-type>
<component-class>org.springframework.faces.ui.ProgressiveCommandLink</component-class>
<component-class>org.springframework.faces.ui.ProgressiveUICommand</component-class>
</component>
<component>
<component-type>spring.faces.AjaxEventInterceptor</component-type>
<component-class>org.springframework.faces.ui.AjaxEventInterceptor</component-class>
<component-class>javax.faces.component.UICommand</component-class>
</component>
<component>
@@ -79,7 +79,7 @@
<component>
<component-type>spring.faces.ValidateAll</component-type>
<component-class>org.springframework.faces.ui.ValidateAll</component-class>
<component-class>org.springframework.faces.ui.DynamicComponent</component-class>
</component>
<render-kit>
@@ -87,31 +87,31 @@
<renderer>
<component-family>javax.faces.Command</component-family>
<renderer-type>spring.faces.ProgressiveCommandButton</renderer-type>
<renderer-type>spring.faces.ProgressiveCommandButtonRenderer</renderer-type>
<renderer-class>org.springframework.faces.ui.ProgressiveCommandButtonRenderer</renderer-class>
</renderer>
<renderer>
<component-family>javax.faces.Command</component-family>
<renderer-type>spring.faces.ProgressiveCommandLink</renderer-type>
<renderer-type>spring.faces.ProgressiveCommandLinkRenderer</renderer-type>
<renderer-class>org.springframework.faces.ui.ProgressiveCommandLinkRenderer</renderer-class>
</renderer>
<renderer>
<component-family>javax.faces.Command</component-family>
<renderer-type>spring.faces.AjaxEventInterceptor</renderer-type>
<renderer-type>spring.faces.AjaxEventInterceptorRenderer</renderer-type>
<renderer-class>org.springframework.faces.ui.AjaxEventInterceptorRenderer</renderer-class>
</renderer>
<renderer>
<component-family>spring.faces.Advisor</component-family>
<renderer-type>spring.faces.DojoAdvisor</renderer-type>
<renderer-class>org.springframework.faces.ui.DojoAdvisorRenderer</renderer-class>
<component-family>spring.faces.Decoration</component-family>
<renderer-type>spring.faces.DojoDecorationRenderer</renderer-type>
<renderer-class>org.springframework.faces.ui.DojoDecorationRenderer</renderer-class>
</renderer>
<renderer>
<component-family>spring.faces.Advisor</component-family>
<renderer-type>spring.faces.ValidateAll</renderer-type>
<component-family>spring.faces.DynamicComponent</component-family>
<renderer-type>spring.faces.ValidateAllRenderer</renderer-type>
<renderer-class>org.springframework.faces.ui.ValidateAllRenderer</renderer-class>
</renderer>

View File

@@ -29,28 +29,28 @@
<tag-name>commandButton</tag-name>
<component>
<component-type>spring.faces.ProgressiveCommandButton</component-type>
<renderer-type>spring.faces.ProgressiveCommandButton</renderer-type>
<renderer-type>spring.faces.ProgressiveCommandButtonRenderer</renderer-type>
</component>
</tag>
<tag>
<tag-name>commandLink</tag-name>
<component>
<component-type>spring.faces.ProgressiveCommandLink</component-type>
<renderer-type>spring.faces.ProgressiveCommandLink</renderer-type>
<renderer-type>spring.faces.ProgressiveCommandLinkRenderer</renderer-type>
</component>
</tag>
<tag>
<tag-name>ajaxEvent</tag-name>
<component>
<component-type>spring.faces.AjaxEventInterceptor</component-type>
<renderer-type>spring.faces.AjaxEventInterceptor</renderer-type>
<renderer-type>spring.faces.AjaxEventInterceptorRenderer</renderer-type>
</component>
</tag>
<tag>
<tag-name>clientTextValidator</tag-name>
<component>
<component-type>spring.faces.DojoClientTextValidator</component-type>
<renderer-type>spring.faces.DojoAdvisor</renderer-type>
<renderer-type>spring.faces.DojoDecorationRenderer</renderer-type>
</component>
</tag>
@@ -58,7 +58,7 @@
<tag-name>clientNumberValidator</tag-name>
<component>
<component-type>spring.faces.DojoClientNumberValidator</component-type>
<renderer-type>spring.faces.DojoAdvisor</renderer-type>
<renderer-type>spring.faces.DojoDecorationRenderer</renderer-type>
</component>
</tag>
@@ -66,7 +66,7 @@
<tag-name>clientCurrencyValidator</tag-name>
<component>
<component-type>spring.faces.DojoClientCurrencyValidator</component-type>
<renderer-type>spring.faces.DojoAdvisor</renderer-type>
<renderer-type>spring.faces.DojoDecorationRenderer</renderer-type>
</component>
</tag>
@@ -74,7 +74,7 @@
<tag-name>clientDateValidator</tag-name>
<component>
<component-type>spring.faces.DojoClientDateValidator</component-type>
<renderer-type>spring.faces.DojoAdvisor</renderer-type>
<renderer-type>spring.faces.DojoDecorationRenderer</renderer-type>
</component>
</tag>
@@ -82,7 +82,7 @@
<tag-name>validateAllOnClick</tag-name>
<component>
<component-type>spring.faces.ValidateAll</component-type>
<renderer-type>spring.faces.ValidateAll</renderer-type>
<renderer-type>spring.faces.ValidateAllRenderer</renderer-type>
</component>
</tag>

View File

@@ -35,7 +35,7 @@ public class AjaxViewRootTests extends TestCase {
UIPanel panel = new UIPanel();
panel.setId("bar");
form.getChildren().add(panel);
ProgressiveCommandButton command = new ProgressiveCommandButton();
ProgressiveUICommand command = new ProgressiveUICommand();
command.setId("baz");
panel.getChildren().add(command);