/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.faces.application;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.List;
import javax.el.ValueExpression;
import javax.el.ExpressionFactory;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
/**
* <p class="changed_added_2_0"><strong class="changed_modified_2_2">
* NavigationCase</strong>
* represents a <code><navigation-case></code> in the navigation
* rule base, as well as the <span class="changed_modified_2_2"><code><from-view-id></code> with
* which this <code><navigation-case></code> is a sibling</span>.</p>
*
* @since 2.0
*/
public class NavigationCase {
private final String fromViewId;
private final String fromAction;
private final String fromOutcome;
private final String condition;
private final String toViewId;
private final String toFlowDocumentId;
private final Map<String,List<String>> parameters;
private final boolean redirect;
private final boolean includeViewParams;
private ValueExpression toViewIdExpr;
private ValueExpression conditionExpr;
private String toString;
private int hashCode;
// ------------------------------------------------------------ Constructors
/**
* <p class="changed_added_2_0"> Construct a new
* <code>NavigationCase</code> based on the provided arguments. See
* section JSF.7.4.2 for how a <code>NavigationCase</code> is used
* by the standard {@link ConfigurableNavigationHandler}</p>
*
* @param fromViewId return from {@link #getFromViewId}
* @param fromAction return from {@link #getFromAction}
* @param fromOutcome return from {@link #getFromOutcome}
* @param condition A string to be interpreted as a
* <code>ValueExpression</code> by a call to {@link #getCondition}
* @param toViewId return from {@link #getToViewId}
* @param parameters return from {@link #getParameters}
* @param redirect return from {@link #isRedirect}
* @param includeViewParams return {@link #isIncludeViewParams}
*/
public NavigationCase(String fromViewId,
String fromAction,
String fromOutcome,
String condition,
String toViewId,
Map<String,List<String>> parameters,
boolean redirect,
boolean includeViewParams) {
this.fromViewId = fromViewId;
this.fromAction = fromAction;
this.fromOutcome = fromOutcome;
this.condition = condition;
this.toViewId = toViewId;
this.toFlowDocumentId = null;
this.parameters = parameters;
this.redirect = redirect;
this.includeViewParams = includeViewParams;
}
/**
* <p class="changed_added_2_0"> Construct a new
* <code>NavigationCase</code> based on the provided arguments. See
* section JSF.7.4.2 for how a <code>NavigationCase</code> is used
* by the standard {@link ConfigurableNavigationHandler}</p>
*
* @param fromViewId return from {@link #getFromViewId}
* @param fromAction return from {@link #getFromAction}
* @param fromOutcome return from {@link #getFromOutcome}
* @param condition A string to be interpreted as a
* <code>ValueExpression</code> by a call to {@link #getCondition}
* @param toViewId return from {@link #getToViewId}
* @param parameters return from {@link #getParameters}
* @param redirect return from {@link #isRedirect}
* @param includeViewParams return {@link #isIncludeViewParams}
*/
public NavigationCase(String fromViewId,
String fromAction,
String fromOutcome,
String condition,
String toViewId,
String toFlowDocumentId,
Map<String,List<String>> parameters,
boolean redirect,
boolean includeViewParams) {
this.fromViewId = fromViewId;
this.fromAction = fromAction;
this.fromOutcome = fromOutcome;
this.condition = condition;
this.toViewId = toViewId;
this.toFlowDocumentId = toFlowDocumentId;
this.parameters = parameters;
this.redirect = redirect;
this.includeViewParams = includeViewParams;
}
// ---------------------------------------------------------- Public Methods
/**
* <p class="changed_added_2_0">Construct an absolute URL to this
* <code>NavigationCase</code> instance using {@link
* javax.faces.application.ViewHandler#getActionURL} on the path
* portion of the url.</p>
*
* @param context the {@link FacesContext} for the current request
*
* @throws MalformedURLException if the process of constructing the
* URL causes this exception to be thrown.
*/
public URL getActionURL(FacesContext context) throws MalformedURLException {
ExternalContext extContext = context.getExternalContext();
return new URL(extContext.getRequestScheme(),
extContext.getRequestServerName(),
extContext.getRequestServerPort(),
context.getApplication().getViewHandler().getActionURL(context, getToViewId(context)));
}
/**
* <p class="changed_added_2_0">Construct an absolute URL to this
* <code>NavigationCase</code> instance using {@link
* javax.faces.application.ViewHandler#getResourceURL} on the path
* portion of the url.</p>
*
* @param context the {@link FacesContext} for the current request
*
* @throws MalformedURLException if the process of constructing the
* URL causes this exception to be thrown.
*/
public URL getResourceURL(FacesContext context) throws MalformedURLException {
ExternalContext extContext = context.getExternalContext();
return new URL(extContext.getRequestScheme(),
extContext.getRequestServerName(),
extContext.getRequestServerPort(),
context.getApplication().getViewHandler().getResourceURL(context, getToViewId(context)));
}
/**
* <p class="changed_added_2_0">Construct an absolute URL suitable for a
* "redirect" to this <code>NavigationCase</code> instance using {@link
* javax.faces.application.ViewHandler#getRedirectURL} on the path
* portion of the url.</p>
*
* @param context the {@link FacesContext} for the current request
*
* @throws MalformedURLException if the process of constructing the
* URL causes this exception to be thrown.
*/
public URL getRedirectURL(FacesContext context) throws MalformedURLException {
ExternalContext extContext = context.getExternalContext();
return new URL(extContext.getRequestScheme(),
extContext.getRequestServerName(),
extContext.getRequestServerPort(),
context.getApplication().getViewHandler().getRedirectURL(context,
getToViewId(context),
SharedUtils.evaluateExpressions(context, getParameters()),
isIncludeViewParams()));
}
/**
* <p class="changed_added_2_0">Construct an absolute URL suitable for a
* bookmarkable link to this <code>NavigationCase</code> instance using {@link
* javax.faces.application.ViewHandler#getBookmarkableURL} on the path
* portion of the url. This URL may include view parameters specified
* as metadata within the view.</p>
*
* @param context the {@link FacesContext} for the current request
*
* @throws MalformedURLException if the process of constructing the
* URL causes this exception to be thrown.
*/
public URL getBookmarkableURL(FacesContext context) throws MalformedURLException {
ExternalContext extContext = context.getExternalContext();
return new URL(extContext.getRequestScheme(),
extContext.getRequestServerName(),
extContext.getRequestServerPort(),
context.getApplication().getViewHandler().getBookmarkableURL(context,
getToViewId(context),
getParameters(),
isIncludeViewParams()));
}
/**
* <p class="changed_added_2_0">Return the
* <code><from-view-id></code> of the
* <code><navigation-rule></code> inside which this
* <code><navigation-case></code> is nested.</p>
*/
public String getFromViewId() {
return fromViewId;
}
/**
* <p class="changed_added_2_0">Return the <code><from-action>
* for this <code><navigation-case></code></code></p>
*/
public String getFromAction() {
return fromAction;
}
/**
* <p class="changed_added_2_0">Return the <code><from-outcome>
* for this <code><navigation-case></code></code></p>
*/
public String getFromOutcome() {
return fromOutcome;
}
/**
* <p class="changed_added_2_0">Evaluates the <code><to-view-id></code>
* for this <code><navigation-case></code></p>
*
* @param context the {@link FacesContext} for the current request
*
* @return the view ID that should be navigated to
*/
public String getToViewId(FacesContext context) {
if (toViewIdExpr == null) {
ExpressionFactory factory =
context.getApplication().getExpressionFactory();
toViewIdExpr = factory.createValueExpression(context.getELContext(),
toViewId,
String.class);
}
String result = (String) toViewIdExpr.getValue(context.getELContext());
if (result.charAt(0) != '/') {
result = '/' + result;
}
return result;
}
/**
* <p class="changed_added_2_2">If this navigation case represents
* a flow invocation, this property is the documentId in which the flow
* whose id is given by the return from {@link #getFromOutcome()} is
* defined. Implementations must override this method to return
* the value defined in the corresponding application configuration resources
* element. The base implementation returns the empty string.</p>
*
* @since 2.2
*/
public String getToFlowDocumentId() {
return toFlowDocumentId;
}
/**
* <p class="changed_added_2_0">Test if this navigation case has an
* associated <code><if></code> element.
*
* @return <code>true</code> if there's an <code><if></code>
* element associated with this <code><navigation-case></code>,
* otherwise <code>false</code>
*/
public boolean hasCondition() {
return (condition != null);
}
/**
* <p class="changed_added_2_0">Evaluates the
* <code><if></code> for this
* <code><navigation-case></code>, if any. The expression to
* be evaluated is passed into the constructor as a string. When
* the expression is evaluated, its value must be coerced into a
* <code>boolean</code> per the normal EL coercion rules.</p>
*
* @param context the {@link FacesContext} for the current request
*
* @return <code>null</code> if there is no <code><if></code> element
* associated with this <code><navigation-case></code>, otherwise
* return the evaluation result of the condition
*
* @throws any exceptions encountered during the process of
* evaluating the expression or obtaining its value.
*/
public Boolean getCondition(FacesContext context) {
if (conditionExpr == null && condition != null) {
ExpressionFactory factory =
context.getApplication().getExpressionFactory();
conditionExpr = factory.createValueExpression(context.getELContext(),
condition,
Boolean.class);
}
return ((conditionExpr != null)
? (Boolean) conditionExpr.getValue(context.getELContext())
: null);
}
/**
* <p class="changed_added_2_0">Return the parameters to be included
* for navigation cases requiring a redirect. If no parameters are
* defined, <code>null</code> will be returned. The keys in the
* <code>Map</code> are parameter names. For each key, the
* corresponding value is a <code>List</code> of unconverted
* values.</p>
*/
public Map<String, List<String>> getParameters() {
return parameters;
}
/**
* <p class="changed_added_2_0">Return the
* <code><redirect></code> value for this
* <code><navigation-case></code>. This will be
* <code>true</code> if the new view should be navigated to via a
* {@link javax.faces.context.ExternalContext#redirect(String)}</p>
*/
public boolean isRedirect() {
return redirect;
}
/**
* <p class="changed_added_2_0">Return the
* <code><redirect></code> value for this
* <code><navigation-case></code>. This will be
* <code>true</code> if the view parametets should be encoded into
* the redirect URL (only applies to redirect case)</p>
*/
public boolean isIncludeViewParams() {
return includeViewParams;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
NavigationCase that = (NavigationCase) o;
return (redirect == that.redirect
&& !(fromAction != null
? !fromAction.equals(that.fromAction)
: that.fromAction != null)
&& !(fromOutcome != null
? !fromOutcome.equals(that.fromOutcome)
: that.fromOutcome != null)
&& !(condition != null
? !condition.equals(that.condition)
: that.condition != null)
&& !(fromViewId != null
? !fromViewId.equals(that.fromViewId)
: that.fromViewId != null)
&& !(toViewId != null
? !toViewId.equals(that.toViewId)
: that.toViewId != null)
&& !(toFlowDocumentId != null
? !toFlowDocumentId.equals(that.toFlowDocumentId)
: that.toFlowDocumentId != null)
&& !(parameters != null
? !parameters.equals(that.parameters)
: that.parameters != null));
}
@Override
public int hashCode() {
if (hashCode == 0) {
int result = fromViewId != null ? fromViewId.hashCode() : 0;
result = 31 * result + (fromAction != null
? fromAction.hashCode()
: 0);
result = 31 * result + (fromOutcome != null
? fromOutcome.hashCode()
: 0);
result = 31 * result + (condition != null
? condition.hashCode()
: 0);
result = 31 * result + (toViewId != null ? toViewId.hashCode() : 0);
result = 31 * result + (toFlowDocumentId != null ? toFlowDocumentId.hashCode() : 0);
result = 31 * result + (redirect ? 1 : 0);
result = 31 * result + (parameters != null ? parameters.hashCode() : 0);
hashCode = result;
}
return hashCode;
}
@Override
public String toString() {
if (toString == null) {
StringBuilder sb = new StringBuilder(64);
sb.append("NavigationCase{");
sb.append("fromViewId='").append(fromViewId).append('\'');
sb.append(", fromAction='").append(fromAction).append('\'');
sb.append(", fromOutcome='").append(fromOutcome).append('\'');
sb.append(", if='").append(condition).append('\'');
sb.append(", toViewId='").append(toViewId).append('\'');
sb.append(", faces-redirect=").append(redirect);
sb.append(", includeViewParams=").append(includeViewParams).append('\'');
sb.append(", parameters=").append(((parameters != null) ? parameters.toString() : ""));
sb.append('}');
toString = sb.toString();
}
return toString;
}
}