    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
    012package org.apache.tapestry5.internal.services.ajax;
    013
    014import org.apache.tapestry5.ClientBodyElement;
    015import org.apache.tapestry5.MarkupWriter;
    016import org.apache.tapestry5.internal.InternalConstants;
    017import org.apache.tapestry5.internal.services.PageRenderQueue;
    018import org.apache.tapestry5.internal.services.PageSource;
    019import org.apache.tapestry5.internal.services.RequestPageCache;
    020import org.apache.tapestry5.internal.structure.Page;
    021import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    022import org.apache.tapestry5.ioc.services.TypeCoercer;
    023import org.apache.tapestry5.json.JSONObject;
    024import org.apache.tapestry5.runtime.RenderCommand;
    025import org.apache.tapestry5.services.PartialMarkupRenderer;
    026import org.apache.tapestry5.services.PartialMarkupRendererFilter;
    027import org.apache.tapestry5.services.Request;
    028import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
    029import org.apache.tapestry5.services.ajax.JSONCallback;
    030import org.apache.tapestry5.services.ajax.JavaScriptCallback;
    031import org.apache.tapestry5.services.javascript.JavaScriptSupport;
    032
    033
    034public class AjaxResponseRendererImpl implements AjaxResponseRenderer
    035{
    036    private final PageRenderQueue queue;
    037
    038    private final AjaxFormUpdateController ajaxFormUpdateController;
    039
    040    private final TypeCoercer typeCoercer;
    041
    042    private final JavaScriptSupport javaScriptSupport;
    043
    044    private final RequestPageCache requestPageCache;
    045
    046    private final Request request;
    047
    048    public AjaxResponseRendererImpl(PageRenderQueue queue, AjaxFormUpdateController ajaxFormUpdateController, TypeCoercer typeCoercer, JavaScriptSupport javaScriptSupport, RequestPageCache requestPageCache, Request request)
    049    {
    050        this.queue = queue;
    051        this.ajaxFormUpdateController = ajaxFormUpdateController;
    052        this.typeCoercer = typeCoercer;
    053        this.javaScriptSupport = javaScriptSupport;
    054        this.requestPageCache = requestPageCache;
    055        this.request = request;
    056    }
    057
    058    public AjaxResponseRenderer addRender(String clientId, Object renderer)
    059    {
    060        assert InternalUtils.isNonBlank(clientId);
    061        assert renderer != null;
    062
    063        RenderCommand command = typeCoercer.coerce(renderer, RenderCommand.class);
    064
    065        addFilter(new SingleZonePartialRendererFilter(clientId, command, queue, ajaxFormUpdateController));
    066
    067        return this;
    068    }
    069
    070    public AjaxResponseRenderer addRender(ClientBodyElement zone)
    071    {
    072        assert zone != null;
    073
    074        final String clientId = zone.getClientId();
    075
    076        if (clientId == null)
    077        {
    078            throw new IllegalArgumentException(
    079                    "Attempt to render a ClientBodyElement, probably a Zone, with a null clientId. "
    080                            + "You can solve this by using the id parameter.");
    081        }
    082
    083        addRender(clientId, zone.getBody());
    084
    085        return this;
    086    }
    087
    088    public AjaxResponseRenderer addCallback(final JavaScriptCallback callback)
    089    {
    090        assert callback != null;
    091
    092        addFilter(new PartialMarkupRendererFilter()
    093        {
    094            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
    095            {
    096                renderer.renderMarkup(writer, reply);
    097
    098                callback.run(javaScriptSupport);
    099            }
    100        });
    101
    102        return this;
    103    }
    104
    105    public AjaxResponseRenderer addCallback(final Runnable callback)
    106    {
    107        assert callback != null;
    108
    109        addFilter(new PartialMarkupRendererFilter()
    110        {
    111            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
    112            {
    113                renderer.renderMarkup(writer, reply);
    114
    115                callback.run();
    116            }
    117        });
    118
    119
    120        return this;
    121    }
    122
    123    private boolean isRedirect(JSONObject reply)
    124    {
    125
    126        return reply.has(InternalConstants.PARTIAL_KEY) &&
    127                reply.in(InternalConstants.PARTIAL_KEY).has("redirectURL");
    128    }
    129
    130    public AjaxResponseRenderer addFilter(final PartialMarkupRendererFilter filter)
    131    {
    132        assert filter != null;
    133
    134        queue.addPartialMarkupRendererFilter(new PartialMarkupRendererFilter()
    135        {
    136            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer delete)
    137            {
    138                if (isRedirect(reply))
    139                {
    140                    // Bypass the callback.
    141                    delete.renderMarkup(writer, reply);
    142                    return;
    143                }
    144
    145                filter.renderMarkup(writer, reply, delete);
    146            }
    147        });
    148
    149        return this;
    150    }
    151
    152    public AjaxResponseRenderer addCallback(final JSONCallback callback)
    153    {
    154        assert callback != null;
    155
    156        addFilter(new PartialMarkupRendererFilter()
    157        {
    158            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
    159            {
    160                renderer.renderMarkup(writer, reply);
    161
    162                callback.run(reply);
    163            }
    164        });
    165
    166        return this;
    167    }
    168
    169    @Override
    170    public void setupPartial(String pageName)
    171    {
    172        Page page = requestPageCache.get(pageName);
    173
    174        queue.setRenderingPage(page);
    175
    176        request.setAttribute(InternalConstants.PAGE_NAME_ATTRIBUTE_NAME, page.getName());
    177    }
    178}