001//  Copyright 2011, 2013, 2014 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013
014package org.apache.tapestry5.internal.services.ajax;
015
016import org.apache.tapestry5.ClientBodyElement;
017import org.apache.tapestry5.MarkupWriter;
018import org.apache.tapestry5.internal.InternalConstants;
019import org.apache.tapestry5.internal.services.PageRenderQueue;
020import org.apache.tapestry5.ioc.internal.util.InternalUtils;
021import org.apache.tapestry5.ioc.services.TypeCoercer;
022import org.apache.tapestry5.json.JSONObject;
023import org.apache.tapestry5.runtime.RenderCommand;
024import org.apache.tapestry5.services.PartialMarkupRenderer;
025import org.apache.tapestry5.services.PartialMarkupRendererFilter;
026import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
027import org.apache.tapestry5.services.ajax.JSONCallback;
028import org.apache.tapestry5.services.ajax.JavaScriptCallback;
029import org.apache.tapestry5.services.javascript.JavaScriptSupport;
030
031
032public class AjaxResponseRendererImpl implements AjaxResponseRenderer
033{
034    private final PageRenderQueue queue;
035
036    private final AjaxFormUpdateController ajaxFormUpdateController;
037
038    private final TypeCoercer typeCoercer;
039
040    private final JavaScriptSupport javaScriptSupport;
041
042    public AjaxResponseRendererImpl(PageRenderQueue queue, AjaxFormUpdateController ajaxFormUpdateController, TypeCoercer typeCoercer, JavaScriptSupport javaScriptSupport)
043    {
044        this.queue = queue;
045        this.ajaxFormUpdateController = ajaxFormUpdateController;
046        this.typeCoercer = typeCoercer;
047        this.javaScriptSupport = javaScriptSupport;
048    }
049
050    public AjaxResponseRenderer addRender(String clientId, Object renderer)
051    {
052        assert InternalUtils.isNonBlank(clientId);
053        assert renderer != null;
054
055        RenderCommand command = typeCoercer.coerce(renderer, RenderCommand.class);
056
057        addFilter(new SingleZonePartialRendererFilter(clientId, command, queue, ajaxFormUpdateController));
058
059        return this;
060    }
061
062    public AjaxResponseRenderer addRender(ClientBodyElement zone)
063    {
064        assert zone != null;
065
066        final String clientId = zone.getClientId();
067        
068        if (clientId == null)
069        {
070            throw new IllegalArgumentException(
071                    "Attempt to render a ClientBodyElement, probably a Zone, with a null clientId. "
072                    + "You can solve this by using the id parameter.");
073        }
074        
075        addRender(clientId, zone.getBody());
076
077        return this;
078    }
079
080    public AjaxResponseRenderer addCallback(final JavaScriptCallback callback)
081    {
082        assert callback != null;
083
084        addFilter(new PartialMarkupRendererFilter()
085        {
086            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
087            {
088                renderer.renderMarkup(writer, reply);
089
090                callback.run(javaScriptSupport);
091            }
092        });
093
094        return this;
095    }
096
097    public AjaxResponseRenderer addCallback(final Runnable callback)
098    {
099        assert callback != null;
100
101        addFilter(new PartialMarkupRendererFilter()
102        {
103            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
104            {
105                renderer.renderMarkup(writer, reply);
106
107                callback.run();
108            }
109        });
110
111
112        return this;
113    }
114
115    private boolean isRedirect(JSONObject reply)
116    {
117
118        return reply.has(InternalConstants.PARTIAL_KEY) &&
119                reply.in(InternalConstants.PARTIAL_KEY).has("redirectURL");
120    }
121
122    public AjaxResponseRenderer addFilter(final PartialMarkupRendererFilter filter)
123    {
124        assert filter != null;
125
126        queue.addPartialMarkupRendererFilter(new PartialMarkupRendererFilter()
127        {
128            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer delete)
129            {
130                if (isRedirect(reply))
131                {
132                    // Bypass the callback.
133                    delete.renderMarkup(writer, reply);
134                    return;
135                }
136
137                filter.renderMarkup(writer, reply, delete);
138            }
139        });
140
141        return this;
142    }
143
144    public AjaxResponseRenderer addCallback(final JSONCallback callback)
145    {
146        assert callback != null;
147
148        addFilter(new PartialMarkupRendererFilter()
149        {
150            public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
151            {
152                renderer.renderMarkup(writer, reply);
153
154                callback.run(reply);
155            }
156        });
157
158        return this;
159    }
160}