001: /*
002: * Copyright 2004-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.springframework.webflow.engine.builder;
017:
018: import org.springframework.binding.convert.ConversionContext;
019: import org.springframework.binding.convert.support.ConversionServiceAwareConverter;
020: import org.springframework.binding.expression.Expression;
021: import org.springframework.util.StringUtils;
022: import org.springframework.webflow.engine.NullViewSelector;
023: import org.springframework.webflow.engine.ViewSelector;
024: import org.springframework.webflow.engine.support.ApplicationViewSelector;
025: import org.springframework.webflow.engine.support.ExternalRedirectSelector;
026: import org.springframework.webflow.engine.support.FlowDefinitionRedirectSelector;
027: import org.springframework.webflow.execution.support.ApplicationView;
028: import org.springframework.webflow.execution.support.ExternalRedirect;
029: import org.springframework.webflow.execution.support.FlowDefinitionRedirect;
030: import org.springframework.webflow.execution.support.FlowExecutionRedirect;
031:
032: /**
033: * Converter that converts an encoded string representation of a view selector
034: * into a {@link ViewSelector} object that will make selections at runtime.
035: * <p>
036: * This converter supports the following encoded forms:
037: * <ul>
038: * <li>empty - will result in a {@link NullViewSelector}.</li>
039: * <li>"viewName" - will result in an {@link ApplicationViewSelector} that
040: * returns an {@link ApplicationView} ViewSelection with the provided view name expression.</li>
041: * <li>"redirect:<viewName>" - will result in an
042: * {@link ApplicationViewSelector} that returns an {@link FlowExecutionRedirect}
043: * to a flow execution URL.</li>
044: * <li>"externalRedirect:<url>" - will result in an
045: * {@link ExternalRedirectSelector} that returns an {@link ExternalRedirect} to a
046: * URL.</li>
047: * <li>"flowRedirect:<flowId>" - will result in a
048: * {@link FlowDefinitionRedirectSelector} that returns a {@link FlowDefinitionRedirect}
049: * to a flow.</li>
050: * <li>"bean:<id>" - will result in usage of a custom
051: * <code>ViewSelector</code> bean implementation.</li>
052: * </ul>
053: *
054: * @see org.springframework.webflow.execution.ViewSelection
055: * @see org.springframework.webflow.engine.ViewSelector
056: *
057: * @author Keith Donald
058: * @author Erwin Vervaet
059: */
060: public class TextToViewSelector extends ConversionServiceAwareConverter {
061:
062: /**
063: * Prefix used when the encoded view name wants to specify that a redirect
064: * is required. ("redirect:")
065: */
066: public static final String REDIRECT_PREFIX = "redirect:";
067:
068: /**
069: * Prefix used when the encoded view name wants to specify that a redirect
070: * to an external URL is required. ("externalRedirect:")
071: */
072: public static final String EXTERNAL_REDIRECT_PREFIX = "externalRedirect:";
073:
074: /**
075: * Prefix used when the encoded view name wants to specify that a redirect
076: * to a flow definition is requred. ("flowRedirect:")
077: */
078: public static final String FLOW_DEFINITION_REDIRECT_PREFIX = "flowRedirect:";
079:
080: /**
081: * Prefix used when the user wants to use a ViewSelector implementation
082: * managed by a bean factory. ("bean:")
083: */
084: private static final String BEAN_PREFIX = "bean:";
085:
086: /**
087: * Locator to use for loading custom ViewSelector beans.
088: */
089: private FlowServiceLocator flowServiceLocator;
090:
091: /**
092: * Create a new text to ViewSelector converter. Custom ViewSelector implemenations
093: * will be looked up using given service locator.
094: */
095: public TextToViewSelector(FlowServiceLocator flowServiceLocator) {
096: this .flowServiceLocator = flowServiceLocator;
097: setConversionService(flowServiceLocator.getConversionService());
098: }
099:
100: public Class[] getSourceClasses() {
101: return new Class[] { String.class };
102: }
103:
104: public Class[] getTargetClasses() {
105: return new Class[] { ViewSelector.class };
106: }
107:
108: protected Object doConvert(Object source, Class targetClass,
109: ConversionContext context) throws Exception {
110: String encodedView = (String) source;
111: if (!StringUtils.hasText(encodedView)) {
112: return NullViewSelector.INSTANCE;
113: } else {
114: return convertEncodedViewSelector(encodedView);
115: }
116: }
117:
118: /**
119: * Convert given encoded view into an appropriate view selector.
120: * @param encodedView the encoded view selector
121: * @return the view selector
122: */
123: protected ViewSelector convertEncodedViewSelector(String encodedView) {
124: if (encodedView.startsWith(REDIRECT_PREFIX)) {
125: String viewName = encodedView.substring(REDIRECT_PREFIX
126: .length());
127: Expression viewNameExpr = (Expression) fromStringTo(
128: Expression.class).execute(viewName);
129: // just show the application view using a redirect
130: return new ApplicationViewSelector(viewNameExpr, true);
131: } else if (encodedView.startsWith(EXTERNAL_REDIRECT_PREFIX)) {
132: String externalUrl = encodedView
133: .substring(EXTERNAL_REDIRECT_PREFIX.length());
134: Expression urlExpr = (Expression) fromStringTo(
135: Expression.class).execute(externalUrl);
136: return new ExternalRedirectSelector(urlExpr);
137: } else if (encodedView
138: .startsWith(FLOW_DEFINITION_REDIRECT_PREFIX)) {
139: String flowRedirect = encodedView
140: .substring(FLOW_DEFINITION_REDIRECT_PREFIX.length());
141: Expression redirectExpr = (Expression) fromStringTo(
142: Expression.class).execute(flowRedirect);
143: return new FlowDefinitionRedirectSelector(redirectExpr);
144: } else if (encodedView.startsWith(BEAN_PREFIX)) {
145: String id = encodedView.substring(BEAN_PREFIX.length());
146: return flowServiceLocator.getViewSelector(id);
147: } else {
148: Expression viewNameExpr = (Expression) fromStringTo(
149: Expression.class).execute(encodedView);
150: return new ApplicationViewSelector(viewNameExpr);
151: }
152: }
153: }
|