001// Copyright 2004, 2005 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// limitations under the License.
014
015package org.apache.tapestry.engine;
016
017import java.io.IOException;
018import java.util.HashMap;
019import java.util.Map;
020
021import org.apache.hivemind.ApplicationRuntimeException;
022import org.apache.hivemind.util.Defense;
023import org.apache.tapestry.IAction;
024import org.apache.tapestry.IComponent;
025import org.apache.tapestry.IPage;
026import org.apache.tapestry.IRequestCycle;
027import org.apache.tapestry.StaleSessionException;
028import org.apache.tapestry.Tapestry;
029import org.apache.tapestry.services.LinkFactory;
030import org.apache.tapestry.services.ResponseRenderer;
031import org.apache.tapestry.services.ServiceConstants;
032import org.apache.tapestry.web.WebRequest;
033import org.apache.tapestry.web.WebSession;
034
035/**
036 * A context-sensitive service related to {@link org.apache.tapestry.form.Form}and
037 * {@link org.apache.tapestry.link.ActionLink}. Encodes the page, component and an action id in the
038 * service context.
039 * 
040 * @author Howard Lewis Ship
041 * @since 1.0.9
042 * @deprecated To be removed in 4.1.
043 */
044
045public class ActionService implements IEngineService
046{
047    /** @since 4.0 */
048    private ResponseRenderer _responseRenderer;
049
050    /** @since 4.0 */
051    private LinkFactory _linkFactory;
052
053    /** @since 4.0 */
054    private static final String ACTION = "action";
055
056    /** @since 4.0 */
057    private WebRequest _request;
058
059    /** @since 4.0 */
060    private IRequestCycle _requestCycle;
061
062    public ILink getLink(boolean post, Object parameter)
063    {
064        Defense.isAssignable(parameter, ActionServiceParameter.class, "parameter");
065
066        ActionServiceParameter asp = (ActionServiceParameter) parameter;
067
068        IComponent component = asp.getComponent();
069        IPage activePage = _requestCycle.getPage();
070        IPage componentPage = component.getPage();
071
072        Map parameters = new HashMap();
073
074        boolean stateful = _request.getSession(false) != null;
075
076        parameters.put(ServiceConstants.COMPONENT, component.getIdPath());
077        parameters.put(ServiceConstants.PAGE, activePage.getPageName());
078        parameters.put(ServiceConstants.CONTAINER, activePage == componentPage ? null
079                : componentPage.getPageName());
080        parameters.put(ACTION, asp.getActionId());
081        parameters.put(ServiceConstants.SESSION, stateful ? "T" : null);
082
083        return _linkFactory.constructLink(this, post, parameters, true);
084    }
085
086    public void service(IRequestCycle cycle) throws IOException
087    {
088        String componentId = cycle.getParameter(ServiceConstants.COMPONENT);
089        String componentPageName = cycle.getParameter(ServiceConstants.CONTAINER);
090        String activePageName = cycle.getParameter(ServiceConstants.PAGE);
091        String actionId = cycle.getParameter(ACTION);
092        boolean activeSession = cycle.getParameter(ServiceConstants.SESSION) != null;
093
094        IPage page = cycle.getPage(activePageName);
095
096        // Setup the page for the rewind, then do the rewind.
097
098        cycle.activate(page);
099
100        IPage componentPage = componentPageName == null ? page : cycle.getPage(componentPageName);
101
102        IComponent component = componentPage.getNestedComponent(componentId);
103
104        IAction action = null;
105
106        try
107        {
108            action = (IAction) component;
109        }
110        catch (ClassCastException ex)
111        {
112            throw new ApplicationRuntimeException(EngineMessages.wrongComponentType(
113                    component,
114                    IAction.class), component, null, ex);
115        }
116
117        // Only perform the stateful check if the application was stateful
118        // when the URL was rendered.
119
120        if (activeSession && action.getRequiresSession())
121        {
122            WebSession session = _request.getSession(false);
123
124            if (session == null || session.isNew())
125                throw new StaleSessionException(EngineMessages.requestStateSession(component),
126                        componentPage);
127
128        }
129
130        cycle.rewindPage(actionId, action);
131
132        // During the rewind, a component may change the page. This will take
133        // effect during the second render, which renders the HTML response.
134
135        // Render that response.
136
137        _responseRenderer.renderResponse(cycle);
138    }
139
140    public String getName()
141    {
142        return Tapestry.ACTION_SERVICE;
143    }
144
145    /** @since 4.0 */
146    public void setResponseRenderer(ResponseRenderer responseRenderer)
147    {
148        _responseRenderer = responseRenderer;
149    }
150
151    /** @since 4.0 */
152    public void setLinkFactory(LinkFactory linkFactory)
153    {
154        _linkFactory = linkFactory;
155    }
156
157    /** @since 4.0 */
158    public void setRequest(WebRequest request)
159    {
160        _request = request;
161    }
162
163    /** @since 4.0 */
164    public void setRequestCycle(IRequestCycle requestCycle)
165    {
166        _requestCycle = requestCycle;
167    }
168}