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.IComponent; 024 import org.apache.tapestry.IDirect; 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 * Implementation of the direct service, which encodes the page and component id in the service 037 * context, and passes application-defined parameters as well. 038 * 039 * @author Howard Lewis Ship 040 * @since 1.0.9 041 */ 042 043 public class DirectService implements IEngineService 044 { 045 /** @since 4.0 */ 046 protected ResponseRenderer _responseRenderer; 047 048 /** @since 4.0 */ 049 protected LinkFactory _linkFactory; 050 051 /** @since 4.0 */ 052 protected WebRequest _request; 053 054 /** @since 4.0 */ 055 private IRequestCycle _requestCycle; 056 057 public ILink getLink(boolean post, Object parameter) 058 { 059 Defense.isAssignable(parameter, DirectServiceParameter.class, "parameter"); 060 061 DirectServiceParameter dsp = (DirectServiceParameter) parameter; 062 063 IComponent component = dsp.getDirect(); 064 065 // New since 1.0.1, we use the component to determine 066 // the page, not the cycle. Through the use of tricky 067 // things such as Block/InsertBlock, it is possible 068 // that a component from a page different than 069 // the response page will render. 070 // In 1.0.6, we start to record *both* the render page 071 // and the component page (if different). 072 073 IPage activePage = _requestCycle.getPage(); 074 IPage componentPage = component.getPage(); 075 076 Map parameters = new HashMap(); 077 078 boolean stateful = _request.getSession(false) != null; 079 080 parameters.put(ServiceConstants.PAGE, activePage.getPageName()); 081 parameters.put(ServiceConstants.COMPONENT, component.getIdPath()); 082 parameters.put(ServiceConstants.CONTAINER, componentPage == activePage ? null 083 : componentPage.getPageName()); 084 parameters.put(ServiceConstants.SESSION, stateful ? "T" : null); 085 parameters.put(ServiceConstants.PARAMETER, dsp.getServiceParameters()); 086 087 return _linkFactory.constructLink(this, post, parameters, true); 088 } 089 090 public void service(IRequestCycle cycle) throws IOException 091 { 092 String componentId = cycle.getParameter(ServiceConstants.COMPONENT); 093 String componentPageName = cycle.getParameter(ServiceConstants.CONTAINER); 094 String activePageName = cycle.getParameter(ServiceConstants.PAGE); 095 boolean activeSession = cycle.getParameter(ServiceConstants.SESSION) != null; 096 097 IPage page = cycle.getPage(activePageName); 098 099 cycle.activate(page); 100 101 IPage componentPage = componentPageName == null ? page : cycle.getPage(componentPageName); 102 103 IComponent component = componentPage.getNestedComponent(componentId); 104 105 IDirect direct = null; 106 107 try 108 { 109 direct = (IDirect) component; 110 } 111 catch (ClassCastException ex) 112 { 113 throw new ApplicationRuntimeException(EngineMessages.wrongComponentType( 114 component, 115 IDirect.class), component, null, ex); 116 } 117 118 // Check for a StaleSession only when the session was stateful when 119 // the link was created. 120 121 if (activeSession && direct.isStateful()) 122 { 123 WebSession session = _request.getSession(false); 124 125 if (session == null || session.isNew()) 126 throw new StaleSessionException(EngineMessages.requestStateSession(direct), 127 componentPage); 128 } 129 130 Object[] parameters = _linkFactory.extractListenerParameters(cycle); 131 132 triggerComponent(cycle, direct, parameters); 133 134 // Render the response. This will be the active page 135 // unless the direct component (or its delegate) changes it. 136 137 _responseRenderer.renderResponse(cycle); 138 } 139 140 /** @since 4.0 */ 141 142 protected void triggerComponent(IRequestCycle cycle, IDirect direct, Object[] parameters) 143 { 144 cycle.setListenerParameters(parameters); 145 146 direct.trigger(cycle); 147 } 148 149 public String getName() 150 { 151 return Tapestry.DIRECT_SERVICE; 152 } 153 154 /** @since 4.0 */ 155 public void setResponseRenderer(ResponseRenderer responseRenderer) 156 { 157 _responseRenderer = responseRenderer; 158 } 159 160 /** @since 4.0 */ 161 public void setLinkFactory(LinkFactory linkFactory) 162 { 163 _linkFactory = linkFactory; 164 } 165 166 /** @since 4.0 */ 167 public void setRequest(WebRequest request) 168 { 169 _request = request; 170 } 171 172 /** @since 4.0 */ 173 public void setRequestCycle(IRequestCycle requestCycle) 174 { 175 _requestCycle = requestCycle; 176 } 177 }