/* * Copyright 2011 <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> * * 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.ocpsoft.rewrite.faces.navigate; import java.util.List; import java.util.Map.Entry; import org.ocpsoft.common.services.ServiceLoader; import org.ocpsoft.common.util.Assert; import org.ocpsoft.rewrite.faces.RewriteNavigationHandler; import org.ocpsoft.rewrite.servlet.spi.ResourcePathResolver; import org.ocpsoft.urlbuilder.Address; import org.ocpsoft.urlbuilder.AddressBuilder; import org.ocpsoft.urlbuilder.AddressBuilderPath; /** * Helper class to build JSF action outcomes. * * @author Christian Kaltepoth */ public class Navigate { private final String viewId; private final ParameterMap parameters = new ParameterMap(); private boolean redirect = true; private Navigate(String viewId) { this.viewId = viewId; } /** * Create a new {@link Navigate} instance that will invoke navigation to the specified View ID. * <p> * Query parameters to be provided to the destination View ID may be supplied via {@link #with(CharSequence, Object)}. * * @param viewId the destination View ID */ public static Navigate to(String viewId) { Assert.notNull(viewId, "viewId must not be null"); return new Navigate(viewId); } /** * Create a new {@link Navigate} instance that will invoke navigation to the specified {@link Class}. For instance, * if the class specifies a {@literal @}Join rule, this would generate a navigation case targeting the * {@link Address} for the defined resource. * <p> * Query parameters to be provided to the destination View ID may be supplied via {@link #with(CharSequence, Object)}. * * @see ResourcePathResolver * * @param clazz the target {@link Class} */ public static Navigate to(Class<?> clazz) { Assert.notNull(clazz, "clazz must not be null"); @SuppressWarnings("unchecked") Iterable<ResourcePathResolver> resolvers = ServiceLoader.load(ResourcePathResolver.class); for (ResourcePathResolver resolver : resolvers) { String viewId = resolver.resolveFrom(clazz); if (viewId != null) { return new Navigate(viewId); } } throw new IllegalArgumentException("Unable to find the resource path for: " + clazz.getName()); } /** * Set a query parameter to be passed to the specified View Id. * * @param The query parameter name. * @param The query parameter value. */ public Navigate with(CharSequence name, Object value) { Assert.notNull(name, "name must not be null"); if (value != null) { parameters.put(name.toString(), value.toString()); } return this; } /** * Specify that navigation should be performed using JavaServer Faces non-redirecting navigation. */ public Navigate withoutRedirect() { redirect = false; return this; } /** * Build and return the fully constructed navigation {@link String}. */ public String build() { if (redirect) { return buildRedirectOutcome(); } else { return buildStandardOutcome(); } } /** * Builds a special outcome processed by {@link RewriteNavigationHandler} */ private String buildRedirectOutcome() { AddressBuilderPath builderPath = AddressBuilder.begin().pathEncoded(viewId); for (Entry<String, List<String>> param : parameters.entrySet()) { String[] values = param.getValue().toArray(new String[param.getValue().size()]); builderPath.queryEncoded(param.getKey(), (Object[]) values); } String url = builderPath.toString(); return RewriteNavigationHandler.REDIRECT_PREFIX + url; } /** * Builds a standard JSF 2.0 implicit navigation outcome */ private String buildStandardOutcome() { StringBuilder outcome = new StringBuilder(); outcome.append(viewId); boolean first = true; for (Entry<String, List<String>> param : parameters.entrySet()) { for (String value : param.getValue()) { outcome.append(first ? '?' : '&'); outcome.append(param.getKey()); outcome.append('='); outcome.append(value); first = false; } } return outcome.toString(); } @Override public String toString() { return build(); } }