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.annotations.ImmutableSessionPersistedObject;
016import org.apache.tapestry5.internal.InternalConstants;
017import org.apache.tapestry5.ioc.internal.util.InternalUtils;
018import org.apache.tapestry5.services.PageRenderLinkSource;
019
020import java.io.Serializable;
021
022/**
023 * A way of capturing the name of a page and the page activation context so that, at a future date,
024 * the page can be invoked with that data. This kind of callback is very useful when creating more
025 * complicated workflows, where access to a page is "interrupted" with some operation before
026 * returning (via a callback) to the original flow.
027 *
028 * Since the callback is serializable, it can be stored in the session.
029 * 
030 * @since 5.2.0
031 */
032@ImmutableSessionPersistedObject
033public class PageCallback implements Serializable
034{
035    private static final long serialVersionUID = -8067619978636824702L;
036
037    private String pageName;
038
039    private String[] activationContext;
040
041    public PageCallback(String pageName, String[] activationContext)
042    {
043        assert InternalUtils.isNonBlank(pageName);
044        this.pageName = pageName;
045        assert activationContext != null;
046        this.activationContext = activationContext;
047    }
048
049    public PageCallback(String pageName, EventContext activationContext)
050    {
051        this(pageName, activationContext.toStrings());
052    }
053
054    public PageCallback(String pageName)
055    {
056        this(pageName, InternalConstants.EMPTY_STRING_ARRAY);
057    }
058
059    public String getPageName()
060    {
061        return pageName;
062    }
063
064    @Override
065    public String toString()
066    {
067        if (hasActivationContext())
068            return String.format("PageCallback[%s %s]", pageName, activationContextDescription());
069
070        return String.format("PageCallback[%s]", pageName);
071    }
072
073    /** Does the activation context have any values? Used, typically, inside an override of {@link #toString()}. */
074    protected final boolean hasActivationContext()
075    {
076        return activationContext.length > 0;
077    }
078
079    /**
080     * Returns the activation context as a string of value separated by slashes. Typically used inside
081     * an override of {@link #toString()}.
082     */
083    protected final String activationContextDescription()
084    {
085        StringBuilder builder = new StringBuilder();
086
087        String sep = "";
088
089        for (String c : activationContext)
090        {
091            builder.append(sep);
092            builder.append(c);
093
094            sep = "/";
095        }
096
097        return builder.toString();
098    }
099
100    /**
101     * Converts the callback (the page name and activation context) to a link; such a link may be
102     * returned from a event handler method to cause Tapestry to redirect to the page. Most of the
103     * details
104     * are encapsulated inside the {@link PageRenderLinkSource} service.
105     * 
106     * @param linkSource
107     *            used to generate the link
108     * @return link corresponding to this callback
109     */
110    public Link toLink(PageRenderLinkSource linkSource)
111    {
112        return linkSource.createPageRenderLinkWithContext(pageName, (Object[]) activationContext);
113    }
114}