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 public ILink getLink(IRequestCycle cycle, boolean post, Object parameter) 060 { 061 Defense.isAssignable(parameter, ActionServiceParameter.class, "parameter"); 062 063 ActionServiceParameter asp = (ActionServiceParameter) parameter; 064 065 IComponent component = asp.getComponent(); 066 IPage activePage = cycle.getPage(); 067 IPage componentPage = component.getPage(); 068 069 Map parameters = new HashMap(); 070 071 boolean stateful = _request.getSession(false) != null; 072 073 parameters.put(ServiceConstants.SERVICE, getName()); 074 parameters.put(ServiceConstants.COMPONENT, component.getIdPath()); 075 parameters.put(ServiceConstants.PAGE, activePage.getPageName()); 076 parameters.put(ServiceConstants.CONTAINER, activePage == componentPage ? null 077 : componentPage.getPageName()); 078 parameters.put(ACTION, asp.getActionId()); 079 parameters.put(ServiceConstants.SESSION, stateful ? "T" : null); 080 081 return _linkFactory.constructLink(cycle, post, parameters, true); 082 } 083 084 public void service(IRequestCycle cycle) throws IOException 085 { 086 String componentId = cycle.getParameter(ServiceConstants.COMPONENT); 087 String componentPageName = cycle.getParameter(ServiceConstants.CONTAINER); 088 String activePageName = cycle.getParameter(ServiceConstants.PAGE); 089 String actionId = cycle.getParameter(ACTION); 090 boolean activeSession = cycle.getParameter(ServiceConstants.SESSION) != null; 091 092 IPage page = cycle.getPage(activePageName); 093 094 // Setup the page for the rewind, then do the rewind. 095 096 cycle.activate(page); 097 098 IPage componentPage = componentPageName == null ? page : cycle.getPage(componentPageName); 099 100 IComponent component = componentPage.getNestedComponent(componentId); 101 102 IAction action = null; 103 104 try 105 { 106 action = (IAction) component; 107 } 108 catch (ClassCastException ex) 109 { 110 throw new ApplicationRuntimeException(EngineMessages.wrongComponentType( 111 component, 112 IAction.class), component, null, ex); 113 } 114 115 // Only perform the stateful check if the application was stateful 116 // when the URL was rendered. 117 118 if (activeSession && action.getRequiresSession()) 119 { 120 WebSession session = _request.getSession(false); 121 122 if (session == null || session.isNew()) 123 throw new StaleSessionException(EngineMessages.requestStateSession(component), 124 componentPage); 125 126 } 127 128 cycle.rewindPage(actionId, action); 129 130 // During the rewind, a component may change the page. This will take 131 // effect during the second render, which renders the HTML response. 132 133 // Render that response. 134 135 _responseRenderer.renderResponse(cycle); 136 } 137 138 public String getName() 139 { 140 return Tapestry.ACTION_SERVICE; 141 } 142 143 /** @since 4.0 */ 144 public void setResponseRenderer(ResponseRenderer responseRenderer) 145 { 146 _responseRenderer = responseRenderer; 147 } 148 149 /** @since 4.0 */ 150 public void setLinkFactory(LinkFactory linkFactory) 151 { 152 _linkFactory = linkFactory; 153 } 154 155 /** @since 4.0 */ 156 public void setRequest(WebRequest request) 157 { 158 _request = request; 159 } 160 }