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}