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 }