001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005// http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5;
014
015import org.apache.tapestry5.commons.util.CommonsUtils;
016import org.apache.tapestry5.http.Link;
017import org.apache.tapestry5.http.annotations.ImmutableSessionPersistedObject;
018import org.apache.tapestry5.ioc.internal.util.InternalUtils;
019import org.apache.tapestry5.services.PageRenderLinkSource;
020
021import java.io.Serializable;
022
023/**
024 * A way of capturing the name of a page and the page activation context so that, at a future date,
025 * the page can be invoked with that data. This kind of callback is very useful when creating more
026 * complicated workflows, where access to a page is "interrupted" with some operation before
027 * returning (via a callback) to the original flow.
028 *
029 * Since the callback is serializable, it can be stored in the session.
030 * 
031 * @since 5.2.0
032 */
033@ImmutableSessionPersistedObject
034public class PageCallback implements Serializable
035{
036    private static final long serialVersionUID = -8067619978636824702L;
037
038    private String pageName;
039
040    private String[] activationContext;
041
042    public PageCallback(String pageName, String[] activationContext)
043    {
044        assert InternalUtils.isNonBlank(pageName);
045        this.pageName = pageName;
046        assert activationContext != null;
047        this.activationContext = activationContext;
048    }
049
050    public PageCallback(String pageName, EventContext activationContext)
051    {
052        this(pageName, activationContext.toStrings());
053    }
054
055    public PageCallback(String pageName)
056    {
057        this(pageName, CommonsUtils.EMPTY_STRING_ARRAY);
058    }
059
060    public String getPageName()
061    {
062        return pageName;
063    }
064
065    @Override
066    public String toString()
067    {
068        if (hasActivationContext())
069            return String.format("PageCallback[%s %s]", pageName, activationContextDescription());
070
071        return String.format("PageCallback[%s]", pageName);
072    }
073
074    /** Does the activation context have any values? Used, typically, inside an override of {@link #toString()}. */
075    protected final boolean hasActivationContext()
076    {
077        return activationContext.length > 0;
078    }
079
080    /**
081     * Returns the activation context as a string of value separated by slashes. Typically used inside
082     * an override of {@link #toString()}.
083     */
084    protected final String activationContextDescription()
085    {
086        StringBuilder builder = new StringBuilder();
087
088        String sep = "";
089
090        for (String c : activationContext)
091        {
092            builder.append(sep);
093            builder.append(c);
094
095            sep = "/";
096        }
097
098        return builder.toString();
099    }
100
101    /**
102     * Converts the callback (the page name and activation context) to a link; such a link may be
103     * returned from a event handler method to cause Tapestry to redirect to the page. Most of the
104     * details
105     * are encapsulated inside the {@link PageRenderLinkSource} service.
106     * 
107     * @param linkSource
108     *            used to generate the link
109     * @return link corresponding to this callback
110     */
111    public Link toLink(PageRenderLinkSource linkSource)
112    {
113        return linkSource.createPageRenderLinkWithContext(pageName, (Object[]) activationContext);
114    }
115}