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    
015    package org.apache.tapestry.engine;
016    
017    import java.io.IOException;
018    import java.util.HashMap;
019    import java.util.Map;
020    
021    import org.apache.hivemind.ApplicationRuntimeException;
022    import org.apache.hivemind.util.Defense;
023    import org.apache.tapestry.IAction;
024    import org.apache.tapestry.IComponent;
025    import org.apache.tapestry.IPage;
026    import org.apache.tapestry.IRequestCycle;
027    import org.apache.tapestry.StaleSessionException;
028    import org.apache.tapestry.Tapestry;
029    import org.apache.tapestry.services.LinkFactory;
030    import org.apache.tapestry.services.ResponseRenderer;
031    import org.apache.tapestry.services.ServiceConstants;
032    import org.apache.tapestry.web.WebRequest;
033    import 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    
045    public 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    }