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